@X @~
~V7 56 2 -5
~D10
~H                    MUSS
~
~
~D10
~H            SYS163
~D10
~MMANCHESTER UNIVERSITY  -  CONFIDENTIAL~
~
~
                                                           ISSUE 10~
~V9 -1
~P
~V9 1
~YSYS163
~S~M~OSYS IMPLEMENTATION DESCRIPTION
~
~
~M~OSection 16 Version 3
~S~OSection 16.3 File System (with Remote Access)
~S~O1. General Description
~BThis module provides commands for filing and retrieving segments on local mach
ines as well as remote ones.
It maintains a hierarchical directory structure for each user, in
which each directory may have a number of files and subdirectories.
Facilities are provided for a process to switch to any directory
in the user's tree of directories. Also a user can selectively permit another
user to access any of his files or catalogue the contents of any of his director
ies.

~S~O2. Interfaces
Other modules used~
   Section 1 (Coordinator)~
   Section 3 (Drum management)~
   Section 8 (Clocks)~
   Section 13 (Process management)~
   Section 14 (Virtual store management)~
   Section 15 (Message System)~
   Section 17 (User management)~
   Section 18 (Network management)~
   Section 20 (Process zero)~
Organisational commands~
   OPEN.DIR (DIRECTORY PATH)~
   OPEN.FILE (FILEPATH, USERNAME, SEGMENT, ACCESS)~
   FILE (FILEPATH, USERNAME, SEGMENT)~
   DELETE.FILE (FILEPATH, USERNAME)~
   RENAME.FILE (OLD FILEPATH, USERNAME, NEW FILENAME)~
   CATALOGUE.DIR (DIRECTORY PATH, USERNAME)~
   READ.FILE.STATUS (FILEPATH, USERNAME)~
   PERMIT (FILEPATH, PERMITTED USER, ACCESS, USERNAME)~
   CATALOGUE.PERMIT (DIRECTORY PATH, USERNAME)~
   NAME.DIR (NEWNAME, FILEMANAGER, MACHINE, INITIAL INFORMATION)~
Command level interface procedures~
   CLOSE.FILE (SYSTEM SEGMENT)~
~S~O2.1 Hardware Interface
   None.~
~S~O2.2 Software Interface
~
1) CLOSE.FILE (SYSTEM SEGMENT)
~BThis procedure is called by the virtual store manager whenever
a user releases a segment which is already a file.
~
~
~S~O3. Implementation
~S~O3.1 Outline of Operation
~BInitially each user of the system has a directory, however it is possible to
introduce new subdirectories and organize them as a tree of directories.
For each user, the file system resources under his control, the
 position and size of his directories and the hierarchical
relationship between them are kept in a data structure known as the User Master
Block (USER.MB). Hence it is necessary to access the user master block in any fi
le operation
involving directories and/or files. To keep the number of disc transfers at an a
cceptable level, a number
of user master blocks are kept in (main) store at any point in time. When a user
 master block required for the next file operation is not currently
in (main) store, it will replace the least recently used user master block alrea
dy in store.
Two copies of each user master block are kept on disc at any one time. A contigu
ous
 area of disc, starting at a fixed address, is reserved and treated as an array
with one
entry for each copy of a user master block (i.e. two successive entries per user
).
~BAnother data structure known as the System Master Block (SYS.MB) is used to id
entify the most
up to date version of each user master block.
Space is allocated at a fixed address on the disc for two copies of the system m
aster block.
Whenever changes to a directory are made, the directory concerned is
written to a fresh area of the disc, the user master block and system master blo
ck are updated and written to
the appropriate disc copies in turn. Thus, if the machine fails during updating
the directory, user master block or system master block, the existing
 directories and at least one copy of the  user master block and system master b
lock are secure and valid.
~BA generation number is kept within the system master block, and this is increm
ented
whenever an updated system master block is written to disc.
Thus, on restarting, the latest version of the system master block (and hence
the latest versions of all the user master blocks and directories) can be select
ed by examining the two
 versions of the system master block on disc, and selecting the one with the lat
est generation number.
~BUsers are able to share files. A user may "PERMIT" a file to be
accessed by another user. The user receiving the permission can access the file,
 according to the
permission granted, and is allowed to obtain information about the file such
as size and time of creation. Whenever a non-zero username is specified as a par
ameter of one of the file organisational
commands, the permissions associated with the required directory are checked to
see if
the current user may perform the required operations. The permissions associated
 with a directory cannot
be accessed directly by users.
~BPermit entries associated with a directory occupy the area at the
beginning of the block allocated to the directory. They are followed by
entries which describe the files in the directory.
~BWhen a file is opened, an entry is made in a table called the system
file table (SFT). This has an entry corresponding to each system segment, and ho
lds
the identification of the file.
~BA data structure known as REMOTE.DIRS is associated
with each process. Users are able to perform remote file
operations , on files under the control of a different file manager, by
 specifying username, password and the required directory of a remote user
and associating a new name with them in a NAME.DIR command. An entry is made
in the REMOTE.DIRS, of the current process, which will include a short identific
ation of remote user and his directory.
 If a newname previously
defined in a NAME.DIR command is used as a username
parameter of a file command, a message is send to the
appropriate file manager to perform the specified command.
~BThe concurrency control of redundant copies are not directly
taken care by the system.
 The "user bits" of the file
STATUS variable are available to the user for implementing
sophisticated consistency mechanisms to be used in conjuntion with the
primitives already available.



~S~O3.2 Data structures
~V1 0
~
~T% 27
~

FILE.VARS
~IA type of the variables kept within each PRB, for monitoring the
file usage of a process.~
   :USER.ID
~IThe identification of the user who has created the process.~
   :DIR.ID
~IThe identification of the directory currently open.~
DIR.ENTRY
~IThe type of  entry within a directory. ~
~IThis has two formats:~
   :NO.OF.FILES
~INumber of files within the directory.~
   :FILESTORE.USED
~IAmount of filestore occupied (in blocks).~
   :NO.OF.FILES.PERMITTED
~INumber of permit entries kept in the directory.~
   :NO.OF.USERS.PERMITTED
~INumber of users receiving permissions.~
~IThis form is only applicable to the first entry in the directory.
Subsequent entries either correspond to permit entries (see PERMIT.TYPE) or
 provide information about files kept in the directory. File entries have the fo
rm:~
   :FILE.NAME
~
   :STATUS
~
   :F.SIZE
~ISize of the file.~
   :CREATE.TIME
~
~
   :UPDATE.TIME
~
~
   :FILE.ID
~IUnique File Identifier.~
   :DISC.ADDR
~IStarting disc address of the file (in blocks).~
USER.MB.ENTRY
~IThe format of entries within USER.MB.TABLE.~
   :DIR.NAME~
   :DIR.DISC.ADDR
~IDisc address of the (sub) directory.~
   :DIR.SIZE
~ISize of the (sub) directory in pages.~
   :NEXT.LEVEL
~IThe index into user master block identifying the first subdirectory of this
directory.~
   :SAME.LEVEL
~IThe index into the user master block indentifying a subdirectory in the same l
evel as this one.~
USER.MB.TYPE
~IDefines the structure of a user master block.~
   :TOTAL.FILE.SPACE
~ISpecifies the total file space (in all subdirectories) currently utilised by t
he user.~
   :TOTAL.NO.OF.FILES
~IIndicates the total number of files (in all subdirectories) currently owned by
 the user.~
   :USER.MB.TABLE
~IThis is a vector of USER.MB.ENTRY, which holds all the information concerning
a user's tree of directories. There is one entry per subdirectory. Entry zero
identifies the original (root) directory of the user.~
SYS.MB.ENTRY
~IThe format of a system master block.~
   :LATEST.VERSION
~IA vector indexed by user identification, specifying the latest version of each
 user master block.~
   :GEN.NO
~IThe generation number of the system master block.~
SFT.ENTRY
~IThe format of the entries in the system file table (SFT).~
   :FILE.IDENT
~IIdentification of an open file.~
   :COUNT
~ICount of shared access to that file (-1 if exlusively open).~
PERMIT.TYPE
~IThe format of permit entries kept in a directory.~
   :PERMIT.FNAME
~IThe file to be assigned permissions.~
   :PERMITTED.USERS
~IA vector holding the user id's of users allowed to access
the file specified by "PERMIT.FNAME".~
   :ACCESSES
~IA vector indicating the permissions available to individual users. There is
a one
 to one correspondence between entries in this vector and those in "PERMITTED.US
ERS".~
REMOTE.DIR.TYPE
~IThe format of entries in the REMOTE.DIRS.~
   :N.NAME
~IThe name which is defined to be used in a remote file command.~
   :SHORT.ID
~IThis is the identification, in the remote machine, of the remote directory spe
cified
in a NAME.DIR command. It will be supplied to the relevant file manager in subse
quent file operations involving the remote directory.~
   :FILMAN.NAME
~IName of a specific file manager process, in the remote machine, responsible fo
r
handling remote file operation.~
   :MACHINE.NAME
IName of the machine in which the remote directory is kept.~
   :DEST
~IA vector of 4 INTEGER entries keeping the destination information
about the file management process on the remote machine. The first
two entries hold the SPN (including machine number) and PID respectively. The th
ird entry
specify the destination mode. The fourth enrty is the destination
sequence number (initially zero) which is incremented each time
a remote file operation involves that directory.~
REMOTE.DIRS
~IA vector of REMOTE.DIR.TYPE holding all the remote definitions.
~
MAPPED.UMB.ENTRY
~IThe format of entries in MAPPED.UMB.TABLE.~
   :UMB.ID
~IThe user identification of a user master block currently in (main) store.~
   :COUNT
~IAn indication of how often the user master block has been used since
transferred to (main) store.~
MAPPED.UMB.TABLE
~IA vector of MAPPED.UMB.ENTRY which identifies the user master blocks currently
 available (in the main store).~
MAPPED.UMB.TABLE.SIZE
~IMaximum number of user master blocks which can be available in main store
at any point in time.~
NO.OF.REMOTE.DIRS
~IMaximum number of remote definitions a process may have.~
SFT
~IA vector of type SFT.ENTRY, with an entry for each system file number
(system segment number), indicating if a segment is also a file, and if so,
to whom it belongs.~
CURRENT.DIR.ID
~IThe identification of directory currently accessible.~
CURRENT.DIR.SIZE
~IThe size of the currently accessible directory.~
CURRENT.DIR.ADDR
~IThe disc address of the currently accessible directory.~
OLD.DIR.SIZE
~IThe size of the accessible directory before the last file operation.~
OLD.DIR.ADDR
~IThe disc address previously occupied by the directory before the last file ope
ration.~
CURRENT.SYS.MB.ADDR
~IDisc address of the latest version of the system master block.~
FILE.TRANSFER.ADDR
~IDisc address of the next file system transfer.~
DIR.ENTRY.SIZE
~IA literal giving the size of a directory entry (in bytes).~
CURRENT.UMB.ID
~IIdentification of the user master block currently accessible.~
CURRENT.UMB.ADDR
~IDisc address of the latest version of the user master block currently accessib
le.~
CURRENT.UMB.FRAME
~IThis is an index into MAPPED.UMB.TABLE identifying the currently accessible
user master block among those available in (main) store.~
USER.MB.SIZE
~ISize of a user master block in pages.~
MAX.DIR.ENTRY
~IMaximum number of file and permit entries which can be kept in a directory.~
DIR.SEG.ADDR
~IThe address of the directory within the segment into which it is transferred.~
NO.OF.DIRS
~IMaximum no of (sub)directories that a user can own.~
SYS.MB.START.ADDR
~IThe disc address of the first (even numbered) system master block.~
USER.MB.START.ADDR
~IThe disc address of the area allocated to user master blocks.~
~S~O3.3 Special Notes
~BNone.
~Y
~V9 -1
~P
~D15
~HFLOWCHARTS
~
~
~H                SYS163
~V9 -1
~F
@TITLE SYS16(3,11)

@COL 1S-2R-3R-4R-5R-6F

@FLOW 1-2-3-4-5-6

@BOX 1.0
FILE SYSTEM
@BOX 4.0
PROCEDURES IN MODULE
   INT1 FILE TRANSFER
   CMD1 OPEN DIR
   CMD2 OPEN FILE
   CMD3 FILE
   CMD4 DELETE FILE
   CMD5 RENAME FILE
   CMD8 CATALOGUE FILES
   CMD9 READ FILE STATUS
   CMD10 START FILE REQUEST
   CMD11 END FILE REQUEST
   CMD12 SECURE DIR
   CMD13 FIND FILE ENTRY
   CMD14 ALLOCATE FILE ENTRY
   CMD15 DELETE FILE ENTRY
   CMD16 CLOSE FILE
   CMD17 INIT FILES
   CMD18 TINI FILES
   CMD19 PERMIT
   CMD20 GET DIR
   CMD21 GET SYS MB
   CMD22 CATALOGUE PERMIT
   CMD23 NAME DIR
   CMD24 CHECK REMOTE
   CMD25 REMOTE FILE REQUEST
   CMD26 DELETE USER DIR
   CMD27 CHECK NAME
   CMD28 CREATE FILE SEGMENT
   CMD29 CREATE FILE X SEGMENT
   CMD30 CREATE SUB DIR
   CMD31 DELETE SUB DIR
   CMD32 VALIDATE PATH
   CMD33 GET USER MB
   CMD34 SECURE USER MB
   CMD35 COMPARE NAME
   CMD36 RELEASE DIR NAME
   CMD38 STORE NAME
   CMD39 CHANGE ROOT DIR
   CMD40 CHANGE FILE SIZE
   TSK1 FILE TASK
   TSK2 INIT FILE TASK
   TSK3 INIT FILE DISC
@BOX 6.0
END
@BOX 1.1
#SYS16/1
MODULE SYS16 (OPEN.DIR, OPEN.FILE, FILE, DELETE.FILE, RENAME.FILE,
   CATALOGUE.FILES, READ.FILE.STATUS, PERMIT, CLOSE.FILE,
   CATALOGUE.PERMIT, INIT.FILES, TINI.FILES, DELETE.USER.DIR,
   CREATE.SUBDIR, DELETE.SUBDIR,
   NAME.DIR, RELEASE.DIR.NAME, CHANGE.ROOT.DIR, CHANGE.FILE.SIZE,
   FILE.VARS, REMOTE.DIR.TYPE, STATS.TYPE,
   FILE.TASK, INIT.FILE.TASK,
   CREATE.FILE.SEGMENT, CREATE.FILE.X.SEGMENT);
@BOX 2.1
TYPE SFT.ENTRY IS
   INTEGER32 FILE.IDENT
   INTEGER8 COUNT;
TYPE PERMIT.TYPE IS
   LOGICAL8 [16] PERMIT.FNAME
   INTEGER16 [MAX.PERMITTED.USERS] PERMITTED.USERS
   LOGICAL8 [MAX.PERMITTED.USERS] ACCESSES;
TYPE DISPLAY.PERMIT.ENTRY IS
   LOGICAL8 [16] F.NAME
   LOGICAL64 USER
   LOGICAL8 ACCESS;
TYPE DIR.ENTRY IS
   INTEGER16 NO.OF.FILES, FILE.STORE.USED
   INTEGER16 NO.OF.FILES.PERMITTED, NO.OF.USERS.PERMITTED
OR
   LOGICAL8 [16] FILE.NAME
   INTEGER16 STATUS, F.SIZE, C.SIZE
   INTEGER32 CREATE.TIME, UPDATE.TIME, FILE.ID
   INTEGER32 DISC.ADDR
   LOGICAL8 [2] FILLER;
TYPE SYS.MB.ENTRY IS
   LOGICAL8 [NO.OF.USERS] LATEST.VERSION
   INTEGER8 [SYS.MB.FILLER.SIZE] FILLER
   INTEGER32 GEN.NO;
TYPE USER.MB.ENTRY IS
   LOGICAL8 [16] DIR.NAME
   INTEGER32 DIR.DISC.ADDR
   INTEGER16 DIR.SIZE
   INTEGER32 CREATE.TIME
   INTEGER8 SAME.LEVEL, NEXT.LEVEL;
TYPE USER.MB.TYPE IS
   USER.MB.ENTRY [NO.OF.DIRS] USER.MB.TABLE
   INTEGER16 TOTAL.FILE.SPACE, TOTAL.NO.OF.FILES;
TYPE REMOTE.DIR.TYPE IS
   LOGICAL64 N.NAME, FILMAN.NAME, MACHINE.NAME
   INTEGER16 SHORT.ID
   INTEGER [4] DEST
OR
   INTEGER REMOTE.LINK;
TYPE FILE.VARS IS
   INTEGER16 USER.ID, DIR.ID
   INTEGER16 [NO.OF.REMOTE.DIRS] REMOTE.TABLE;
TYPE MAPPED.UMB.ENTRY IS
   INTEGER16 MAPPED.UMB.ID, COUNT;
TYPE STATS.TYPE IS
  INTEGER FILES.OPENED, FILES.CREATED, FILES.UPDATED;
TYPE ADDRESS8 IS
   ADDR [LOGICAL8] ADDRESS;
@BOX 3.1
*GLOBAL 5;
INTEGER CURRENT.DIR.ID, CURRENT.DIR.SIZE, CURRENT.DIR.ADDR, CURRENT.SYS.MB.ADDR;
INTEGER CURRENT.UMB.ID, CURRENT.UMB.ADDR, CURRENT.UMB.FRAME;
INTEGER OLD.DIR.SIZE, OLD.DIR.ADDR;
INTEGER FILE.TRANSFER.ADDR, FILE.TRANSFER.STATUS;
INTEGER MAX.DIR.ENTRY, USER.MB.SIZE, DIR.SEG.ADDR;
ADDR FILE.VARS C.FILE.VARS;
ADDR DIR.ENTRY DIR.0;
ADDR [DIR.ENTRY] DIR;
ADDR USER.MB.TYPE USER.MB;
ADDR SYS.MB.ENTRY SYS.MB;
ADDR [PERMIT.TYPE] PERMISSIONS;
ADDR FILE.SEG.ADDR;
ADDR STATS.TYPE STATS;
INTEGER REMOTE.FREE;
*GLOBAL 28;
REMOTE.DIR.TYPE [NO.OF.SYS.REMOTE.DIRS] REMOTE.DIRS;
*GLOBAL 28;
MAPPED.UMB.ENTRY [MAPPED.UMB.TABLE.SIZE] MAPPED.UMB.TABLE;
SFT.ENTRY [SYS14.NO.OF.SYS.SEGS] SFT;
LITERAL / INTEGER TRANSFER.FAIL = %1601, REMOTE.SEGMENT = 0;::VERIFY VALUE FOR R
EMOTE SEGMENT
LITERAL / INTEGER MAX.UMB.COUNT = 4;
LITERAL / ADDR [ADDRESS8] NIL.ADDR =;
LITERAL / ADDR [LOGICAL64] NIL.L64 =;
LITERAL / ADDR [INTEGER] NIL.INT =;
@BOX 4.1
#SYS16/2
@BOX 5.1
*CODE 7;
::*INIT %6000;
PSPEC INIT.SYS16 ();
INIT.SYS16 ();
PROC INIT.SYS16;
MAKE (STATS.TYPE, 0, SYS21.GET.STATS (16)) => STATS;
SYS20.SET.TASK (SYS20.FILE.TASK, 0);
BLOCK.SIZE / DIR.ENTRY.SIZE => MAX.DIR.ENTRY;
NO.OF.DIRS * USER.MB.ENTRY.SIZE + 4 + SYS14.PAGE.SIZE - 1 / SYS14.PAGE.SIZE => U
SER.MB.SIZE;
MAPPED.UMB.TABLE.SIZE * USER.MB.SIZE + 1 * SYS14.PAGE.SIZE => DIR.SEG.ADDR;
END
@BOX 6.1
*END
@END

@TITLE SYS16/1(3,11)

@COL 1S-2R-3R-4R

@FLOW 1-2-3-4

@BOX 1.0
OTHER MODULES REFERENCED
@BOX 4.0
SYS01 COORDINATOR
SYS03 DRUM MANAGER
SYS08 CLOCKS
SYS13 PROCESS MANAGER
SYS14 VIRTUAL STORE MANAGER
SYS17 USER MANAGER
SYS20 PROCESS ZERO
@BOX 1.1
::EXTERNAL ENVIRONMENT
@BOX 2.1
IMPORT LITERAL FILE.MAPPED.SEG, FILE.SEG, PERMIT.MAPPED.SEG,
       DIR.ENTRY.SIZE, USER.MB.ENTRY.SIZE,
       CATALOGUE.MAPPED.SEG,
       NO.OF.DIRS, NO.OF.USERS, SYS.MB.FILLER.SIZE,
       MAX.PERMITTED.USERS, BLOCK.SIZE, MAPPED.UMB.TABLE.SIZE,
       NO.OF.REMOTE.DIRS, NO.OF.SYS.REMOTE.DIRS,
       SYS.MB.START.ADDR, USER.MB.START.ADDR;
ADDR PW0, PW1, PW2, PW3, PW4, PW5, PW6;
LOGICAL64 PWW1, PWW2, PWW3, PWW4;
@BOX 3.1
PSPEC VALIDATE (ADDR, LOGICAL) / INTEGER;
@BOX 4.1
PSPEC SYS01.CHECKIN (INTEGER, INTEGER);
PSPEC SYS01.CHECKOUT (INTEGER, INTEGER);
PSPEC SYS03.TRANSFER.DRUM.BLOCK.PAGES (LOGICAL, INTEGER, INTEGER,
   INTEGER, INTEGER) / INTEGER;
PSPEC SYS03.ALLOCATE.DRUM.BLOCK () / LOGICAL;
PSPEC SYS03.RELEASE.DRUM.BLOCK (LOGICAL);
PSPEC SYS03.RESERVE.DRUM.BLOCK (LOGICAL);
PSPEC SYS03.RESERVE.DRUM.SEGMENT (LOGICAL32, INTEGER);
PSPEC SYS03.DRUM.INITIALISATION.COMPLETE ();
PSPEC SYS03.CHANGE.DRUM.SEGMENT.SIZE (INTEGER, INTEGER);
PSPEC SYS03.SECURE.DRUM.SEGMENT (INTEGER);
PSPEC SYS03.READ.DRUM.SEGMENT.ADDR (INTEGER) / LOGICAL32;
PSPEC TIME.AND.DATE ();
PSPEC SYS12.SYSTEM.ERROR (INTEGER);
IMPORT LITERAL SYS13.NO.OF.PROCS;
INTEGER SYS13.CURRENT.SPN;
PSPEC SYS13.CHECK.PRIV ();
PSPEC LOOK.UP.PROCESS (LOGICAL64, LOGICAL64);
PSPEC SYS13.INT.PROC (LOGICAL, LOGICAL);
PSPEC SYS13.ENTER.INT.LEVEL (ADDR SYS13.INT.PROC, LOGICAL, LOGICAL);
PSPEC SYS13.GET.PRB (INTEGER, INTEGER) / ADDR;
PSPEC NAMES ();
IMPORT LITERAL SYS14.PAGE.SIZE, SYS14.PAGE.SHIFT, SYS14.NO.OF.SYS.SEGS,
    SYS14.X.SEG.SIZE, SYS14.X.SEG;
IMPORT LITERAL ADDR SYS14.SEG.SIZE;
PSPEC SYS14.GET.BLOCK (INTEGER, INTEGER) / INTEGER32;
PSPEC SYS14.UPDATE.BLOCK (INTEGER32);
PSPEC SYS14.REL.BLOCK (INTEGER32);
PSPEC COPY.BLOCK (INTEGER, INTEGER, INTEGER, INTEGER);
PSPEC READ.SEGMENT.STATUS (INTEGER);
PSPEC SYS14.READ.SYS.SEGMENT.STATUS (INTEGER);
PSPEC CREATE.SEGMENT (INTEGER, ADDR);
PSPEC CREATE.X.SEGMENT (INTEGER);
PSPEC SYS14.PROTECT (INTEGER, INTEGER);
PSPEC RELEASE.SEGMENT (INTEGER);
PSPEC SYS14.ALLOCATE.SYS.SEG (INTEGER, INTEGER, INTEGER, INTEGER) / INTEGER;
PSPEC SYS14.ASSIGN.USER.SEGMENT (INTEGER, INTEGER, LOGICAL);
PSPEC SECURE.SEGMENT (INTEGER);
PSPEC MAP (INTEGER, INTEGER, INTEGER);
PSPEC SYS14.CMD.MAP (INTEGER, INTEGER);
PSPEC SYS14.RELEASE.SYS.SEGMENT (INTEGER);
PSPEC WAIT (LOGICAL, INTEGER);
PSPEC SET.CH.STATUS (INTEGER, INTEGER, INTEGER, INTEGER);
PSPEC SEND.MESSAGE (ADDR [LOGICAL8], ADDR [INTEGER],
   INTEGER, INTEGER, INTEGER, LOGICAL);
PSPEC READ.MESSAGE (ADDR [LOGICAL8], ADDR [INTEGER], INTEGER, INTEGER);
IMPORT LITERAL SYS17.NO.OF.FILES, SYS17.FILE.STORE;
PSPEC FIND.U (LOGICAL64, LOGICAL64);
PSPEC SYS17.FIND.NAMES (INTEGER);
PSPEC SYS17.FIND.UID (LOGICAL64);
PSPEC SYS17.GET.USER.PARAM (INTEGER, INTEGER) / INTEGER;
IMPORT LITERAL SYS20.FILE.TASK;
PSPEC SYS20.SET.TASK (INTEGER, INTEGER);
PSPEC SYS21.GET.STATS (INTEGER) / ADDR;
@END

@TITLE SYS16/2(3,11)

@COL 1S

@BOX 1.1
*CODE 2;
::*INIT %6000;
PSPEC FILE.TRANSFER (INTEGER, INTEGER);
   #SYSINT16.1
*CODE 20;
LSPEC OPEN.DIR (ADDR [LOGICAL8]);
LSPEC OPEN.FILE (ADDR [LOGICAL8], LOGICAL64, INTEGER, LOGICAL);
LSPEC FILE (ADDR [LOGICAL8], LOGICAL64, INTEGER);
LSPEC DELETE.FILE (ADDR [LOGICAL8], LOGICAL64);
LSPEC RENAME.FILE (ADDR [LOGICAL8], LOGICAL64, ADDR [LOGICAL8]);
LSPEC CATALOGUE.FILES (ADDR [LOGICAL8], LOGICAL64);
LSPEC READ.FILE.STATUS (ADDR [LOGICAL8], LOGICAL64);
PSPEC START.FILE.REQUEST (ADDR [LOGICAL8], LOGICAL64, LOGICAL) / ADDR [LOGICAL8]
;
PSPEC END.FILE.REQUEST ();
PSPEC SECURE.DIR ();
PSPEC FIND.FILE.ENTRY (ADDR [LOGICAL8]) / INTEGER;
PSPEC ALLOCATE.FILE.ENTRY () / INTEGER;
PSPEC DELETE.FILE.ENTRY (INTEGER);
LSPEC PERMIT (ADDR [LOGICAL8], LOGICAL64, LOGICAL64, LOGICAL64);
PSPEC GET.DIR (INTEGER);
PSPEC GET.SYS.MB (INTEGER);
LSPEC CATALOGUE.PERMIT (ADDR [LOGICAL8], LOGICAL64);
LSPEC NAME.DIR (LOGICAL64, LOGICAL64, LOGICAL64, ADDR [LOGICAL8]);
PSPEC CHECK.REMOTE (LOGICAL64) / INTEGER;
PSPEC DELETE.USER.DIR (INTEGER16) / INTEGER;
PSPEC REMOTE.FILE.REQUEST (INTEGER, INTEGER, ADDR [ADDRESS8], ADDR [LOGICAL64],
ADDR [INTEGER]);
PSPEC CHECK.NAME (ADDR [LOGICAL8]) / INTEGER;
LSPEC CREATE.FILE.SEGMENT (INTEGER, ADDR, ADDR [LOGICAL8], LOGICAL64);
LSPEC CREATE.FILE.X.SEGMENT (INTEGER, ADDR [LOGICAL8], LOGICAL64);
LSPEC CREATE.SUBDIR (ADDR [LOGICAL8]);
LSPEC DELETE.SUBDIR (ADDR [LOGICAL8]);
PSPEC VALIDATE.PATH (ADDR [LOGICAL8], LOGICAL64, LOGICAL);
PSPEC GET.USER.MB (INTEGER);
PSPEC SECURE.USER.MB ();
PSPEC COMPARE.NAME (ADDR [LOGICAL8], ADDR [LOGICAL8]) / INTEGER;
LSPEC RELEASE.DIR.NAME (LOGICAL64);
PSPEC STORE.NAME (ADDR [LOGICAL8], ADDR [LOGICAL8]);
LSPEC CHANGE.ROOT.DIR (LOGICAL64, LOGICAL64);
LSPEC CHANGE.FILE.SIZE (ADDR [LOGICAL8], LOGICAL64, INTEGER);
   #SYSCMD16.1
   #SYSCMD16.2
   #SYSCMD16.3
   #SYSCMD16.4
   #SYSCMD16.5
   #SYSCMD16.8
   #SYSCMD16.9
   #SYSCMD16.10
   #SYSCMD16.11
   #SYSCMD16.12
   #SYSCMD16.13
   #SYSCMD16.14
   #SYSCMD16.15
   #SYSCMD16.19
   #SYSCMD16.20
   #SYSCMD16.21
   #SYSCMD16.22
   #SYSCMD16.23
   #SYSCMD16.24
   #SYSCMD16.26
   #SYSCMD16.27
   #SYSCMD16.28
   #SYSCMD16.29
   #SYSCMD16.30
   #SYSCMD16.31
   #SYSCMD16.32
   #SYSCMD16.33
   #SYSCMD16.34
   #SYSCMD16.35
   #SYSCMD16.36
   #SYSCMD16.38
   #SYSCMD16.39
   #SYSCMD16.40
*CODE 19;
::*INIT %7000;
PSPEC INIT.FILES (ADDR FILE.VARS, INTEGER);
PSPEC TINI.FILES (INTEGER);
   #SYSCMD16.17
   #SYSCMD16.18
*CODE 16;
PSPEC CLOSE.FILE (INTEGER);
::PSPEC REMOTE.FILE.REQUEST (INTEGER, INTEGER, ADDR [LOGICAL8], ADDR [LOGICAL8],
 LOGICAL64, LOGICAL64);
   #SYSCMD16.16
   #SYSCMD16.25
*CODE 4;
PSPEC FILE.TASK ();
PSPEC INIT.FILE.TASK ();
PSPEC INIT.FILE.DISC ();
   #SYSTSK16.1
   #SYSTSK16.2
   #SYSTSK16.3
@END
@TITLE SYSINT16.1(3,11)
@COL 1S-8R-7T-2R-3T-4R-5R-9R-6F

@FLOW 1-8-7NO-2-3OK-4-5-7
@FLOW 7YES-6
@FLOW 3FAIL-9-6

@BOX 1.0
FILE TRANSFER (DIRECTION, OFFSET)
@BOX 2.0
LOCK SPECIFIED BLOCK
INTO CORE
[SYS14]
@BOX 3.0
REQUEST DRUM TRANSFER
INTO BLOCK
[SYS03]
@BOX 4.0
MARK BLOCK ALTERED
IF TRANSFER INTO CORE
[SYS14]
@BOX 5.0
RELEASE LOCKIN ON BLOCK
[SYS14]
@BOX 6.0
END
@BOX 7.0
IS TRANSFER COMPLETE?
@BOX 8.0
FIND ADDRESS AND
SIZE OF TRANSFER
@BOX 9.0
INDICATE FILE TRANSFER FAILED
@BOX 1.1
PROC FILE.TRANSFER (DIRN, OFFSET);
INTEGER32 CORE.ADDR;
INTEGER CORE.PAGE.NO, DRUM.PAGE.NO, FILE.TRANSFER.SIZE;
-1 => CORE.PAGE.NO => DRUM.PAGE.NO;
0 => FILE.TRANSFER.STATUS;
@BOX 2.1
IF SYS14.GET.BLOCK (FILE.SEG, OFFSET + CORE.PAGE.NO)
   => CORE.ADDR < 0 THEN
   SYS12.SYSTEM.ERROR (TRANSFER.FAIL);
FI
@BOX 3.1
IF SYS03.TRANSFER.DRUM.BLOCK.PAGES (FILE.TRANSFER.ADDR, DRUM.PAGE.NO,
    CORE.ADDR ->> SYS14.PAGE.SHIFT, 1, DIRN) /= 0
@BOX 4.1
IF DIRN = 0 THEN
   SYS14.UPDATE.BLOCK (CORE.ADDR);
FI
@BOX 5.1
SYS14.REL.BLOCK (CORE.ADDR);
@BOX 6.1
END
@BOX 7.1
1 +> DRUM.PAGE.NO;
IF 1 +> CORE.PAGE.NO >= FILE.TRANSFER.SIZE
@BOX 8.1
IF OFFSET = 0 THEN
   1 => FILE.TRANSFER.SIZE;
   FILE.TRANSFER.ADDR - 1 => DRUM.PAGE.NO;
   0 => FILE.TRANSFER.ADDR;
ELSE
   IF OFFSET = 1 THEN
      USER.MB.SIZE => FILE.TRANSFER.SIZE;
      1 + (CURRENT.UMB.FRAME * USER.MB.SIZE) => OFFSET;
      FILE.TRANSFER.ADDR - 1 => DRUM.PAGE.NO;
      0 => FILE.TRANSFER.ADDR;
   ELSE
      CURRENT.DIR.SIZE => FILE.TRANSFER.SIZE;
      1 + (MAPPED.UMB.TABLE.SIZE * USER.MB.SIZE) => OFFSET;
   FI
FI
@BOX 9.1
SYS14.REL.BLOCK (CORE.ADDR);
1 => FILE.TRANSFER.STATUS;
@END

@TITLE SYSCMD16.1(3,11)

@COL 1S-7T-2R-9T-3T-4R-5R-6F
@COL 8R

@ROW 2-8

@FLOW 1-7OK-2-9NO-3YES-4-5-6
@FLOW 3NO-5-6
@FLOW 7INVALID-8-6
@FLOW 9YES-4

@BOX 1.0
OPEN DIR (DIRECTORY PATH)
@BOX 2.0
CHECK IN
[SYS01]
@BOX 3.0
DOES SPECIFIED
DIRECTORY EXIST?
@BOX 4.0
SET CURRENT DIRECTORY
TO NEW DIRECTORY
@BOX 5.0
CHECK OUT
[SYS01]
@BOX 6.0
END
@BOX 7.0
VALIDATE DIR PATH
@BOX 8.0
RETURN FAULT STATUS -8
(VALDATE FAIL)
@BOX 9.0
RESET TO ROOT?
@BOX 1.1
PROC OPEN.DIR (DIR.PATH);
INTEGER NEW.DIR, D.PATH.SIZE;
0 => PW0;
@BOX 2.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.IN, 0, 0);
@BOX 3.1
VALIDATE.PATH (DIR.PATH, 0, 0);
PW1 => NEW.DIR;
IF PW0 /= 0
@BOX 4.1
MAKE (FILE.VARS, 0, SYS13.GET.PRB (-1, 16)) => C.FILE.VARS;
NEW.DIR => DIR.ID OF C.FILE.VARS^;
@BOX 5.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.OUT, 0, 0);
@BOX 6.1
END
@BOX 7.1
IF SIZE (DIR.PATH) => D.PATH.SIZE > 0 AND
   [VALIDATE (BYTE (^DIR.PATH^ [0]), %C) /= 0 OR
    VALIDATE (BYTE (^DIR.PATH^ [D.PATH.SIZE - 1]), %C) /= 0]
@BOX 8.1
-8 => PW0;
@BOX 9.1
0 => NEW.DIR;
IF D.PATH.SIZE =< 0
@END

@TITLE SYSCMD16.2(3,11)

@COL 1S-25T-23T-2T-3T-4T-5T-6T-21T-7R-9R-15N-10R-11N-12F
@COL 26R-24R-13R-14R-20T-17R-16N-18N

@ROW 23-26
@ROW 3-13
@ROW 6-14
@ROW 7-20
@ROW 15-16
@ROW 11-18

@FLOW 1-25OK-23LOCAL-2NO-3-4NO-5NO-6NO-21OK-7-9-15-10-11-12
@FLOW 23REMOTE-24-18
@FLOW 2YES-13-18-11
@FLOW 3FAIL-15
@FLOW 4YES-15
@FLOW 5YES-14-16-15
@FLOW 6YES-20NO-17-16
@FLOW 20YES-9
@FLOW 21FAIL-15
@FLOW 25INVALID-26-18-11

@BOX 1.0
OPEN FILE (FILEPATH, USERNAME, SEG, ACCESS)
@BOX 2.0
IS SEGMENT OCCUPIED
OR INVALID?
@BOX 3.0
START FILE REQUEST
[SYSCMD16.10]
@BOX 4.0
IS FILE NON-EXISTENT?
[SYSCMD16.13]
@BOX 5.0
FILE LIMIT EXCEEDED?
@BOX 6.0
IS FILE ALREADY OPEN?
@BOX 7.0
INITIALISE A FILE TABLE ENTRY
@BOX 9.0
OPEN FILE INTO
USERS VIRTUAL STORE
@BOX 10.0
END FILE REQUEST
[SYSCMD16.11]
@BOX 12.0
END
@BOX 13.0
RETURN FAULT STATUS -46
(ILLEGAL SEGMENT SPECIFIED)
@BOX 14.0
RETURN FAULT STATUS -41
(FILE STORE LIMIT EXCEEDED)
@BOX 17.0
RETURN FAULT STATUS -44
(EXCLUSIVE ACCESS FAULT)
@BOX 20.0
SHARED ACCESS ALLOWED?
@BOX 21.0
ALLOCATE SYSTEM SEGMENT
[SYS14]
@BOX 23.0
IS FILE REMOTE?
[SYSCMD16.24]
@BOX 24.0
REQUEST A COPY OF THE FILE FROM
THE FILE MANAGER OF THE
SPECIFIED MACHINE
[SYSCMD16.25]
@BOX 25.0
VALIDATE FILE PATH
@BOX 26.0
RETURN FAULT STATUS -8
(VALIDATE FAIL)
@BOX 1.1
PROC OPEN.FILE (FILE.PATH, U.NAME, SEG, ACCESS);
INTEGER FILE.NO, SSN, REMOTE.DIR.NO, F.PATH.SIZE;
ADDR [LOGICAL8] F.NAME;
LOGICAL64 [1] L64.PARAMS;
INTEGER [1] INT.PARAMS;
ADDRESS8 [1] STRING.PARAMS;
0 => PW0;
@BOX 2.1
IF SEG < 0 THEN
   -6 => PW0;
ELSE
   READ.SEGMENT.STATUS (SEG);
FI
IF PW0 /= -6
@BOX 3.1
START.FILE.REQUEST (FILE.PATH, U.NAME, ACCESS & %17) => F.NAME;
IF PW0 /= 0
@BOX 4.1
IF FIND.FILE.ENTRY (F.NAME) => FILE.NO < 0
@BOX 5.1
PW1 => SSN;
IF FILE.STORE.USED OF DIR.0^ >=
   SYS17.GET.USER.PARAM (CURRENT.UMB.ID, SYS17.FILE.STORE) OR
   NO.OF.FILES OF DIR.0^ >=
   SYS17.GET.USER.PARAM (CURRENT.UMB.ID, SYS17.NO.OF.FILES)
@BOX 6.1
IF SSN >= 0
@BOX 7.1
SYS14.PROTECT (SSN, 1);
FILE.ID => FILE.IDENT OF SFT [SSN];
@BOX 9.1
IF ACCESS & %20 /= 0 THEN
   -1 => COUNT OF SFT [SSN];
FI
1 +> FILES.OPENED OF STATS^;
SYS14.ASSIGN.USER.SEGMENT (SSN, SEG, ACCESS & %1F);
@BOX 10.1
END.FILE.REQUEST ();
@BOX 12.1
END
@BOX 13.1
-46 => PW0;
@BOX 14.1
-41 => PW0;
@BOX 17.1
-44 => PW0;
@BOX 20.1
IF ACCESS & %20 = 0 OR
   COUNT OF SFT [SSN] >= 0
@BOX 21.1
SELECT DIR^ [FILE.NO];
SYS14.ALLOCATE.SYS.SEG (DISC.ADDR,
   F.SIZE, C.SIZE, STATUS) => SSN;
IF PW0 /= 0
@BOX 23.1
IF ACCESS =< 0 THEN
   %1E => ACCESS;
FI
IF CHECK.REMOTE (U.NAME) => REMOTE.DIR.NO >= 0
@BOX 24.1
FILE.PATH => ADDRESS OF STRING.PARAMS [0];
ACCESS => L64.PARAMS [0];
SEG => INT.PARAMS [0];
REMOTE.FILE.REQUEST (REMOTE.DIR.NO, %10,
   ^STRING.PARAMS, ^L64.PARAMS, ^INT.PARAMS);
@BOX 25.1
IF SIZE (FILE.PATH) => F.PATH.SIZE /= 0 AND
   [VALIDATE (BYTE (^FILE.PATH^ [0]), %C) /= 0 OR
    VALIDATE (BYTE (^FILE.PATH^ [F.PATH.SIZE - 1]), %C) /= 0]
@BOX 26.1
-8 => PW0;
@END


@TITLE SYSCMD16.3(3,11)

@COL 1S-30T-2T-23T-34T-3T-4T-31T-5R-6T-7T-8R-9T-10R-11R-29N-12R-13N-14F
@COL 32R-25R-24R-35R-15R-33R-17R-36N-18N

@ROW 2-32
@ROW 5-33
@ROW 3-35
@ROW 4-15
@ROW 7-17
@ROW 13-18
@ROW 23-25
@ROW 29-36
@ROW 34-24

@FLOW 1-30OK-2NO-23LOCAL-34LOCAL-3NO-4-31NO-5-6NO-7-8-9OK-10-11-29-12-13-14
@FLOW 23REMOTE-24-18
@FLOW 2YES-25-18-13
@FLOW 3YES-15-18
@FLOW 4FAIL-29
@FLOW 6YES-17-9
@FLOW 7FAIL-29
@FLOW 9FAIL-29
@FLOW 30INVALID-32-18-13
@FLOW 31YES-33-36-29
@FLOW 34REMOTE-35-18

@BOX 1.0
FILE (FILEPATH, USERNAME, SEG)
@BOX 2.0
IS SEGMENT UNDEFINED?
@BOX 3.0
IS SEGMENT ALREADY A FILE?
@BOX 4.0
START FILE REQUEST
[SYSCMD16.10]
@BOX 5.0
SECURE SEGMENT
[SYS14]
@BOX 6.0
DOES FILE OF THIS NAME
ALREADY EXIST?
[SYSCMD16.13]
@BOX 7.0
ALLOCATE A DIRECTORY ENTRY
[SYSCMD16.14]
@BOX 8.0
INITIALISE DIRECTORY ENTRY
@BOX 9.0
UPDATE DIRECTORY
AND SECURE IT
[SYSCMD16.12]
@BOX 10.0
NOTE SEGMENT IS NOW
FILE
[SYS14]
@BOX 11.0
RELEASE OLD FILE SPACE
IF NECESSARY
[SYS03]
@BOX 12.0
END FILE REQUEST
[SYSCMD16.11]
@BOX 14.0
END
@BOX 15.0
RETURN FAULT STATUS -46
(ILLEGAL SEGMENT SPECIFIED)
@BOX 17.0
NOTE SSN, DISC ADDRESS AND
SIZE OF FILE
@BOX 23.0
IS FILE REMOTE?
[SYSCMD16.24]
@BOX 24.0
FILE THE SEGMENT IN THE
SPECIFIED MACHINE
[SYSCMD16.25]
@BOX 25.0
RETURN FAULT STATUS -46
(ILLEGAL SEGMENT SPECIFIED)
@BOX 30.0
VALIDATE FILE PATH
@BOX 31.0
IS FILE NAME NOT
SPECIFIED OR INCLUDE
ANY INVALID CHARACTERS?
@BOX 32.0
RETURN FAULT STATUS -8
(VALIDATE FAIL)
@BOX 33.0
RETURN FAULT STATUS -48
(INVALID CHARACTER IN FILE/DIRECTORY NAME)
@BOX 34.0
IS SEGMENT REMOTE?
@BOX 35.0
RETURN FAULT STATUS -46
(ILLEGAL SEGMENT SPECIFIED)
@BOX 1.1
PROC FILE (FILE.PATH, U.NAME, SEG);
INTEGER SSN, FILE.NO, CURR.FILE.SSN, CURR.FILE.SIZE, FILE.SIZE,
   FILE.STATUS, FILE.CSIZE, CURR.FILE.ADDR, FILE.ADDR,
   CURR.FILE.STATUS, CURR.FILE.CSIZE, REMOTE.DIR.NO,
   DIFF, F.PATH.SIZE, OPER.TYPE, I, J;
ADDR [LOGICAL8] F.NAME;
INTEGER [1] INT.PARAMS;
ADDRESS8 [1] STRING.PARAMS;
0 => PW0;
@BOX 2.1
SYS14.READ.SYS.SEGMENT.STATUS (SEG);
PW1 => FILE.SIZE;
PW2 => FILE.STATUS;
PW3 => SSN;
PW4 => FILE.CSIZE;
IF PW0 /= 0
@BOX 3.1
IF FILE.IDENT OF SFT [SSN] /= 0
@BOX 4.1
START.FILE.REQUEST (FILE.PATH, U.NAME, %20) => F.NAME;
IF PW0 /= 0
@BOX 5.1
SECURE.SEGMENT (SEG);
SYS14.READ.SYS.SEGMENT.STATUS (SEG);
PWW1 => FILE.ADDR;
TIME.AND.DATE ();
@BOX 6.1
0 => CURR.FILE.SSN;
IF FIND.FILE.ENTRY (F.NAME) => FILE.NO >= 0
@BOX 7.1
IF ALLOCATE.FILE.ENTRY () => FILE.NO < 0
@BOX 8.1
STORE.NAME (F.NAME, ^FILE.NAME OF DIR^ [FILE.NO]);
PWW1 => CREATE.TIME OF DIR^ [FILE.NO];
FILE.SIZE +> FILE.STORE.USED OF DIR.0^;
FILE.SIZE +> TOTAL.FILE.SPACE OF USER.MB^;
1 +> FILES.CREATED OF STATS^;
@BOX 9.1
0 => PW0;
PWW1 => UPDATE.TIME OF DIR^ [FILE.NO];
FILE.SIZE => F.SIZE OF DIR^ [FILE.NO];
FILE.CSIZE => C.SIZE OF DIR^ [FILE.NO];
FILE.STATUS => STATUS OF DIR^ [FILE.NO];
FILE.ADDR => DISC.ADDR OF DIR^ [FILE.NO];
1 + GEN.NO OF SYS.MB^ => FILE.ID OF DIR^ [FILE.NO];
SECURE.DIR ();
IF PW0 /= 0
@BOX 10.1
FILE.ID OF DIR^ [FILE.NO] => FILE.IDENT OF SFT [SSN];
SYS14.PROTECT (SSN, 1);
@BOX 11.1
IF CURR.FILE.SSN < 0 THEN
   SYS14.ALLOCATE.SYS.SEG (CURR.FILE.ADDR, CURR.FILE.SIZE,
      CURR.FILE.CSIZE, CURR.FILE.STATUS) => CURR.FILE.SSN;
   IF PW0 = 0 THEN
      SYS14.RELEASE.SYS.SEGMENT (CURR.FILE.SSN);
   FI
ELSE
   IF CURR.FILE.SSN > 0 THEN
      0 => FILE.IDENT OF SFT [CURR.FILE.SSN];
      SYS14.PROTECT (CURR.FILE.SSN, 0);
   FI
FI
@BOX 12.1
END.FILE.REQUEST ();
@BOX 14.1
END
@BOX 15.1
-46 => PW0;
@BOX 17.1
1 +> FILES.UPDATED OF STATS^;
PW1 => CURR.FILE.SSN;
DISC.ADDR OF DIR^ [FILE.NO] => CURR.FILE.ADDR;
C.SIZE OF DIR^ [FILE.NO] => CURR.FILE.CSIZE;
STATUS OF DIR^ [FILE.NO] => CURR.FILE.STATUS;
F.SIZE OF DIR^ [FILE.NO] => CURR.FILE.SIZE
 - FILE.SIZE => DIFF -> FILE.STORE.USED OF DIR.0^;
DIFF -> TOTAL.FILE.SPACE OF USER.MB^;
@BOX 23.1
IF CHECK.REMOTE (U.NAME) => REMOTE.DIR.NO >= 0
@BOX 24.1
FILE.PATH => ADDRESS OF STRING.PARAMS [0];
SEG => INT.PARAMS [0];
IF FILE.STATUS & REMOTE.SEGMENT /= 0 THEN
   %21 => OPER.TYPE
ELSE
   %20 => OPER.TYPE
FI
REMOTE.FILE.REQUEST (REMOTE.DIR.NO, OPER.TYPE,
   ^STRING.PARAMS, NIL.L64, ^INT.PARAMS);
@BOX 25.1
-46 => PW0;
@BOX 30.1
IF SIZE (FILE.PATH) => F.PATH.SIZE /= 0 AND
   [VALIDATE (BYTE (^FILE.PATH^ [0]), %C) /= 0 OR
    VALIDATE (BYTE (^FILE.PATH^ [F.PATH.SIZE - 1]), %C) /= 0]
@BOX 31.1
IF CHECK.NAME (F.NAME) /= 0
 OR SIZE (F.NAME) =< 0
@BOX 32.1
-8 => PW0;
@BOX 33.1
-48 => PW0;
@BOX 34.1
IF FILE.STATUS & REMOTE.SEGMENT /= 0
@BOX 35.1
-46 => PW0;
@END


@TITLE SYSCMD16.4(3,11)

@COL 1S-25T-23T-2T-3T-4T-5R-6R-7T-8R-9R-10F
@COL 26R-24R-27N

@ROW 23-26
@ROW 10-27
@ROW 2-24

@FLOW 23REMOTE-24-27-10
@FLOW 1-25OK-23LOCAL-2-3NO-4NO-5-6-7OK-8-9-10
@FLOW 25INVALID-26-27
@FLOW 2FAIL-9
@FLOW 3YES-9
@FLOW 4YES-6
@FLOW 7FAIL-9

@BOX 1.0
DELETE FILE (FILENAME, USERNAME)
@BOX 2.0
START FILE REQUEST
[SYSCMD16.10]
@BOX 3.0
IS FILE NON-EXISTENT?
[SYSCMD16.13]
@BOX 4.0
IS FILE OPEN?
@BOX 5.0
REMEMBER DISC ADDRESS OF FILE
@BOX 6.0
DELETE DIRECTORY ENTRY
FOR THE FILE
[SYSCMD16.15]
@BOX 7.0
UPDATE DIRECTORY
ON DISC
[SYSCMD16.12]
@BOX 8.0
RELEASE DISC SPACE
OCCUPIED BY FILE
[SYS03]
@BOX 9.0
END FILE REQUEST
[SYSCMD16.11]
@BOX 10.0
END
@BOX 23.0
IS FILE REMOTE?
[SYSCMD16.24]
@BOX 24.0
DELETE THE REMOTE FILE
[SYSCMD16.25]
@BOX 25.0
VALIDATE FILE PATH
@BOX 26.0
RETURN FAULT STATUS -8
(VALIDATE FAIL)
@BOX 1.1
PROC DELETE.FILE (FILE.PATH, U.NAME);
INTEGER FILE.NO, FILE.SIZE, CURR.FILE.SSN, F.PATH.SIZE,
   FILE.ADDR, REMOTE.DIR.NO, CURR.SIZE, FILE.STATUS;
ADDR [LOGICAL8] F.NAME;
ADDRESS8 [1] STRING.PARAMS;
0 => PW0;
@BOX 2.1
START.FILE.REQUEST (FILE.PATH, U.NAME, %40) => F.NAME;
IF PW0 /= 0
@BOX 3.1
IF FIND.FILE.ENTRY (F.NAME) => FILE.NO < 0
@BOX 4.1
SELECT DIR^ [FILE.NO];
C.SIZE => CURR.SIZE;
STATUS => FILE.STATUS;
F.SIZE => FILE.SIZE;
IF PW1 => CURR.FILE.SSN >= 0
@BOX 5.1
DISC.ADDR => FILE.ADDR;
@BOX 6.1
DELETE.FILE.ENTRY (FILE.NO);
FILE.SIZE -> FILE.STORE.USED OF DIR.0^;
FILE.SIZE -> TOTAL.FILE.SPACE OF USER.MB^;
@BOX 7.1
SECURE.DIR ();
IF PW0 /= 0
@BOX 8.1
IF CURR.FILE.SSN >= 0 THEN
   0 => FILE.IDENT OF SFT [CURR.FILE.SSN];
   SYS14.PROTECT (CURR.FILE.SSN, 0);
ELSE
   SYS14.ALLOCATE.SYS.SEG (FILE.ADDR, FILE.SIZE,
      CURR.SIZE, FILE.STATUS) => CURR.FILE.SSN;
   IF PW0 = 0 THEN
      SYS14.RELEASE.SYS.SEGMENT (CURR.FILE.SSN);
   FI
FI
@BOX 9.1
END.FILE.REQUEST ();
@BOX 10.1
END
@BOX 23.1
IF CHECK.REMOTE (U.NAME) => REMOTE.DIR.NO >= 0
@BOX 24.1
FILE.PATH => ADDRESS OF STRING.PARAMS [0];
REMOTE.FILE.REQUEST (REMOTE.DIR.NO, %30,
       ^STRING.PARAMS, NIL.L64, NIL.INT);
@BOX 25.1
IF SIZE (FILE.PATH) => F.PATH.SIZE /= 0 AND
   [VALIDATE (BYTE (^FILE.PATH^ [0]), %C) /= 0 OR
    VALIDATE (BYTE (^FILE.PATH^ [F.PATH.SIZE - 1]), %C) /= 0]
@BOX 26.1
-8 => PW0;
@END


@TITLE SYSCMD16.5(3,1)

@COL 1S-25T-23T-2T-26T-8T-3T-4R-5R-6R-10N-7F
@COL 27R-24R-28R-9R-29N-11N

@ROW 8-28
@ROW 2-24
@ROW 3-9
@ROW 6-29
@ROW 10-11
@ROW 23-27

@FLOW 23REMOTE-24-11-10
@FLOW 1-25OK-23LOCAL-2-26NO-8NO-3NO-4-5-6-10-7
@FLOW 25INVALID-27-11-10
@FLOW 26YES-28-29-6
@FLOW 2FAIL-6
@FLOW 8YES-9-29
@FLOW 3YES-6

@BOX 1.0
RENAME FILE (OLD FILEPATH, USERNAME, NEW FILENAME)
@BOX 2.0
START FILE REQUEST
[SYSCMD16.10]
@BOX 3.0
IS FILE NON-EXISTENT?
[SYSCMD16.13]
@BOX 4.0
CHANGE NAME IN
FILE DIRECTORY
@BOX 5.0
SECURE DIRECTORY
[SYSCMD16.12]
@BOX 6.0
END FILE REQUEST
[SYSCMD16.11]
@BOX 7.0
END
@BOX 8.0
DOES NEW FILENAME
ALREADY EXIST?
@BOX 9.0
RETURN FAULT STATUS -47
(FILE/DIRECTORY NAME ALREADY EXISTS)
@BOX 23.0
IS FILE REMOTE?
[SYSCMD16.24]
@BOX 24.0
CHANGE THE NAME OF THE
REMOTE FILE [SYSCMD16.25]
@BOX 25.0
VALIDATE FILE PATH
@BOX 26.0
IS NEW FILE NAME
NOT SPECIFIED OR INCLUDE
ANY INVALID CHARACTERS?
@BOX 27.0
RETURN FAULT STATUS -8
(VALIDATE FAIL)
@BOX 28.0
RETURN FAULT STATUS -48
(INVALID CHARACTER IN FILE/DIRECTORY NAME)
@BOX 1.1
PROC RENAME.FILE (O.FILE.PATH, U.NAME, N.FILE.NAME);
INTEGER FILE.NO, REMOTE.DIR.NO, F.PATH.SIZE, F.NAME.SIZE, I, J;
ADDR [LOGICAL8] OF.NAME;
ADDRESS8 [2] STRING.PARAMS;
0 => PW0;
@BOX 2.1
START.FILE.REQUEST (O.FILE.PATH, U.NAME, %80) => OF.NAME;
IF PW0 /= 0
@BOX 3.1
0 => PW0;
IF FIND.FILE.ENTRY (OF.NAME) => FILE.NO < 0
@BOX 4.1
STORE.NAME (N.FILE.NAME, ^FILE.NAME OF DIR^ [FILE.NO]);
@BOX 5.1
SECURE.DIR ();
@BOX 6.1
END.FILE.REQUEST ();
@BOX 7.1
END
@BOX 8.1
IF FIND.FILE.ENTRY (N.FILE.NAME) >= 0
@BOX 9.1
-47 => PW0;
@BOX 23.1
IF CHECK.REMOTE (U.NAME) => REMOTE.DIR.NO >= 0
@BOX 24.1
O.FILE.PATH => ADDRESS OF STRING.PARAMS [0];
N.FILE.NAME => ADDRESS OF STRING.PARAMS [1];
REMOTE.FILE.REQUEST (REMOTE.DIR.NO, %40,
   ^STRING.PARAMS, NIL.L64, NIL.INT);
@BOX 25.1
IF [SIZE (O.FILE.PATH) => F.PATH.SIZE /= 0 AND
    [VALIDATE (BYTE (^O.FILE.PATH^ [0]), %C) /= 0 OR
     VALIDATE (BYTE (^O.FILE.PATH^ [F.PATH.SIZE - 1]), %C) /= 0]]
   OR
   [SIZE (N.FILE.NAME) => F.NAME.SIZE /= 0 AND
    [VALIDATE (BYTE (^N.FILE.NAME^ [0]), %C) /= 0 OR
     VALIDATE (BYTE (^N.FILE.NAME^ [F.NAME.SIZE - 1]), %C) /= 0]]
@BOX 26.1
IF CHECK.NAME (N.FILE.NAME) /= 0
OR F.NAME.SIZE =< 0
@BOX 27.1
-8 => PW0;
@BOX 28.1
-48 => PW0;
@END



@TITLE SYSCMD16.8(3,11)

@COL 1S-14T-2T-3R-4T-5T-6T-17R-18T-7T-8R-19R-9R-10R-11R-12F
@COL 15R-13R-16N

@ROW 2-15
@ROW 3-13
@ROW 12-16

@FLOW 1-14OK-2NO-3-4YES-5YES-6OK-17-18OK-7NO-9-10-11-12
@FLOW 14INVALID-15-16-12
@FLOW 2YES-13-16-12
@FLOW 4NO-11
@FLOW 5NO-18
@FLOW 6FAIL-11
@FLOW 7YES-8-19-10
@FLOW 18FAIL-11

@BOX 1.0
CATALOGUE FILES (DIRECTORY PATH, USER NAME)
@BOX 2.0
IS DIRECTORY REMOTE?
@BOX 3.0
CHECK IN
[SYS01]
@BOX4.0
IS DIRECTORY PATH
VALID?
@BOX 5.0
DOES DIRECTORY HAVE
ANY SUBDIRECTORIES/FILES?
@BOX 6.0
CREATE A SEGMENT FOR
DIRECTORY CATALOGUE
@BOX 7.0
ALL ENTRIES IN THE SUBDIRECTORY
TO BE CATALOGUED?
@BOX 8.0
CATALOGUE ALL ENTRIES
@BOX 9.0
CATALOGUE ENTRIES PERMITTED
TO THIS USER
#SYSCMD16.8.2
@BOX 10.0
RETURN SEGMENT NUMBER,
NUMBER OF FILES AND
SUBDIRECTORIES
@BOX 11.0
CHECK OUT
[SYS01]
@BOX 12.0
END
@BOX 13.0
CATALOGUE REMOTE DIRECTORY
@BOX 14.0
VALIDATE DIRECTORY PATH
@BOX 15.0
RETURN FAILT STATUS -8
(VALIDATE FAIL)
@BOX 17.0
MAP THE SEGMENT
@BOX 18.0
GET UID OF USER
WHOSE DIR IS TO
BE CATALOGUED
@BOX 19.0
GET USER FILE
STORE LIMITS
@BOX 1.1
PROC CATALOGUE.FILES (DIR.PATH, U.NAME);
LITERAL / INTEGER SEG.ENTRY.SIZE = 40;
INTEGER FILE.COUNT, DIR.COUNT, SUB.DIR, SEG.NO, COUNT, FILE.SPACE.USED,
        REMOTE.DIR.NO, REQ.DIR, D.PATH.SIZE, CURR.UID, REQ.UID, USER.FILES,
        USER.SPACE, SUPERIOR, SEG.COUNT, FILE.LIM, STORE.LIM, PTR;
LOGICAL64 CURR.USER;
ADDR [LOGICAL8] SEG8;
ADDR [LOGICAL32] SEG32;
ADDRESS8 [1] STRING.PARAMS;
PSPEC COPY.DIR (INTEGER);
PSPEC COPY.FILE (INTEGER);
::PROCEDURE BODIES
#SYSCMD16.8.1
0 => PW0;
@BOX 2.1
IF CHECK.REMOTE (U.NAME) => REMOTE.DIR.NO >= 0
@BOX 3.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.IN, 0, 0);
@BOX 4.1
VALIDATE.PATH (DIR.PATH, U.NAME, 1);
PW1 => REQ.DIR;
IF PW0 /= 0
@BOX 5.1
0 => SEG.NO;
0 => FILE.COUNT => DIR.COUNT => FILE.SPACE.USED
  => FILE.LIM => STORE.LIM => USER.FILES => USER.SPACE;
SELECT USER.MB^;
NO.OF.FILES OF DIR.0^ => COUNT;
IF NEXT.LEVEL OF USER.MB.TABLE [REQ.DIR] => SUB.DIR < 0
   AND COUNT = 0
@BOX 6.1
CREATE.SEGMENT (-1, (COUNT +31) * SEG.ENTRY.SIZE);
PW1 => SEG.NO;
IF PW0 /= 0
@BOX 7.1
0 => SEG.COUNT;
IF U.NAME /= 0 AND REQ.UID /= CURR.UID AND SUPERIOR < 0
@BOX 8.1
COPY.DIR (SUBDIR);
FOR PTR < COUNT DO
   COPY.FILE (PTR);
OD
@BOX 9.1
::CATALOGUE PERMITTED ENTRIES
#SYSCMD16.8.2
@BOX 10.1
DIR.COUNT => PW1;
FILE.COUNT => PW2;
SEG.NO => PW3;
FILE.LIM =>  PW4;
FILE.SPACE.USED => PW5;
STORE.LIM => PW6;
USER.FILES => PWW1;
USER.SPACE => PWW2;
@BOX 11.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.OUT, 0, 0);
@BOX 12.1
END
@BOX 13.1
DIR.PATH => ADDRESS OF STRING.PARAMS [0];
REMOTE.FILE.REQUEST (REMOTE.DIR.NO, %50,
        ^STRING.PARAMS, NIL.L64, NIL.INT);
@BOX 14.1
IF SIZE (DIR.PATH) => D.PATH.SIZE /= 0 AND
   [VALIDATE (BYTE (^DIR.PATH^ [0]), %C) /= 0 OR
    VALIDATE (BYTE (^DIR.PATH^ [D.PATH.SIZE - 1]), %C) /= 0]
@BOX 15.1
-8 => PW0;
@BOX 17.1
SYS14.CMD.MAP (SEG.NO, CATALOGUE.MAPPED.SEG);
MAKE (LOGICAL8, 32 * (COUNT + 31), PW6 * SYS14.SEG.SIZE) => SEG8;
MAKE (LOGICAL32, 8 * (COUNT + 31), PW6 * SYS14.SEG.SIZE) => SEG32;
@BOX 18.1
MAKE (FILE.VARS, 0, SYS13.GET.PRB (-1, 16)) => C.FILE.VARS;
USER.ID OF C.FILE.VARS^ => CURR.UID;
IF U.NAME /= 0 THEN
   SYS17.FIND.UID (U.NAME);
   PW1 => REQ.UID;
   PW2 => SUPERIOR;
FI
IF PW0 /= 0
@BOX 19.1
SYS17.GET.USER.PARAM (CURRENT.UMB.ID, SYS17.NO.OF.FILES) => FILE.LIM;
SYS17.GET.USER.PARAM (CURRENT.UMB.ID, SYS17.FILE.STORE) => STORE.LIM;
TOTAL.NO.OF.FILES => USER.FILES;
TOTAL.FILE.SPACE => USER.SPACE;
@END
@TITLE SYSCMD16.8.1(3,11)

@COL 1S-2R-3R-6F

@FLOW 1-2-3-6

@BOX 1.0
PROCEDURE BODIES
@BOX 2.0
COPY DIRECTORY NAME
@BOX 3.0
COPY FILE NAME
@BOX 4.0
COPY ALL DIRECTORY NAMES
@BOX 5.0
COPY ALL FILE NAMES
@BOX 6.0
END
@BOX 1.1
BEGIN
@BOX 2.1
PROC COPY.DIR (SUB.DIR);
   INTEGER I, K, L;
   WHILE SUB.DIR >= 0 DO
      SEG.COUNT * (SEG.ENTRY.SIZE) => L / 4 => K;
      1 +> SEG.COUNT;
      1 +> DIR.COUNT;
      SELECT USER.MB.TABLE [SUB.DIR] OF USER.MB^;
      FOR I < 16 DO
         DIR.NAME [I] => SEG8^ [L];
         1 +> L;
      OD
      DIR.SIZE => SEG32^ [K + 4];
      CREATE.TIME => SEG32^ [K + 5];
      DIR.DISC.ADDR => SEG32^ [K + 6];
      SAME.LEVEL => SUB.DIR;
   OD
END
@BOX 3.1
PROC COPY.FILE (PTR);
   INTEGER I, K, L;
   SEG.COUNT * (SEG.ENTRY.SIZE) => L / 4 => K;
   1 +> SEG.COUNT;
   1 +> FILE.COUNT;
   SELECT DIR^ [PTR];
   FOR I < 16 DO
      FILE.NAME [I] => SEG8^ [L];
      1 +> L;
   OD
   STATUS => SEG32^ [K + 4];
   F.SIZE => SEG32^ [K + 5];
   UPDATE.TIME => SEG32^ [K + 6];
   CREATE.TIME => SEG32^ [K + 7];
   DISC.ADDR => SEG32^ [K + 8];
   F.SIZE +> FILE.SPACE.USED;
END
@BOX 6.1
END
@END
@TITLE SYSCMD16.8.2(3,11)

@COL 1S-4T-2T-3T-5R-8F
@COL 6R-7R-9N

@ROW 3-6
@ROW 5-7
@ROW 8-9

@FLOW 1-4YES-2OK-3NO-5-8
@FLOW 2FAIL-6-9-8
@FLOW 3YES-7-9
@FLOW 4NO-8

@BOX 1.0
BEGIN
@BOX 2.0
CATALOGUE PERMIT FILE
@BOX 3.0
ALL FILE NAMES
TO BE CATALOGUED?
@BOX 4.0
ANY FILES IN DIR?
@BOX 5.0
CATALOGUE PERMITTED FILES
@BOX 6.0
RELEASE SEGMENT
@BOX 7.0
COPY ALL FILE NAMES
@BOX 8.0
END
@BOX 1.1
BEGIN
INTEGER PERMIT.COUNT, PERMIT.SEG, PTR, SAVE.PW0, I, K;
ADDR [DISPLAY.PERMIT.ENTRY] DISPLAY.PERMIT;
@BOX 2.1
CATALOGUE.PERMIT (DIR.PATH, U.NAME);
IF PW0 /= 0
@BOX 3.1
PW1 => PERMIT.COUNT;
PW2 => PERMIT.SEG;
SYS14.CMD.MAP (PERMIT.SEG, PERMIT.MAPPED.SEG);
MAKE (DISPLAY.PERMIT.ENTRY, PERMIT.COUNT,
       PW6 * SYS14.SEG.SIZE) => DISPLAY.PERMIT;
FOR I < PERMIT.COUNT DO
   IF COMPARE.NAME (%"ALL",^F.NAME OF
 DISPLAY.PERMIT^ [I]) = 0, ->OUT
OD
OUT:
IF I < PERMIT.COUNT
@BOX 4.1
IF COUNT = 0
@BOX 5.1
-1 => PTR;
0 => K;
WHILE 1 +> PTR < COUNT AND K < PERMIT.COUNT DO
   SELECT DIR^ [PTR];
   FOR I < PERMIT.COUNT DO
      IF COMPARE.NAME (^FILE.NAME,
         ^F.NAME OF DISPLAY.PERMIT^ [I]) = 0 THEN
         COPY.FILE (PTR);
         1 +> K;
         ->NEXT.F;
      FI
   OD
   NEXT.F:
OD
@BOX 6.1
PW0 => SAVE.PW0;
RELEASE.SEGMENT (SEG.NO);
SAVE.PW0 => PW0;
@BOX 7.1
FOR PTR < COUNT DO
   COPY.FILE (PTR);
OD
@BOX 8.1
END
@END

@TITLE SYSCMD16.9(3,11)

@COL 1S-7T-9T-2T-3T-4R-5R-6F
@COL 8R-10R-11N

@ROW 2-10
@ROW 6-11
@ROW 9-8

@FLOW 1-7OK-9LOCAL-2-3NO-4-5-6
@FLOW 7INVALID-8-11-6
@FLOW 9REMOTE-10-11
@FLOW 2FAIL-5
@FLOW 3YES-5

@BOX 1.0
READ FILE STATUS (FILEPATH, USERNAME)
@BOX 2.0
START FILE REQUEST
[SYSCMD16.10]
@BOX 3.0
IS FILE NON-EXISTENT?
@BOX 4.0
READ STATUS INFORMATION
ABOUT THE FILE
@BOX 5.0
END FILE REQUEST
[SYSCMD16.11]
@BOX 6.0
END
@BOX 7.0
VALIDATE FILE PATH
@BOX 8.0
RETURN FAULT STATUS
(VALIDATE FAIL)
@BOX 9.0
IS FILE REMOTE?
@BOX 10.0
GET STATUS OF
REMOTE FILE
@BOX 1.1
PROC READ.FILE.STATUS (FILE.PATH, U.NAME);
INTEGER CURR.FILE.SSN, FILE.NO, F.PATH.SIZE,
         REMOTE.DIR.NO;
ADDRESS8 [1] STRING.PARAMS;
ADDR [LOGICAL8] F.NAME;
0 => PW0;
@BOX 2.1
START.FILE.REQUEST (FILE.PATH, U.NAME, 0) => F.NAME;
IF PW0 /= 0
@BOX 3.1
IF FIND.FILE.ENTRY (F.NAME) => FILE.NO < 0
@BOX 4.1
PW1 => CURR.FILE.SSN;
SELECT DIR^ [FILE.NO];
STATUS => PW1;
F.SIZE <<- SYS14.PAGE.SHIFT => PWW1;
UPDATE.TIME => PWW2;
CREATE.TIME => PWW3;
IF CURR.FILE.SSN >= 0 THEN
   %C !> PW1;
FI
@BOX 5.1
END.FILE.REQUEST ();
@BOX 6.1
END
@BOX 7.1
IF SIZE (FILE.PATH) => F.PATH.SIZE /= 0 AND
   [VALIDATE (BYTE (^FILE.PATH^ [0]), %C) /= 0 OR
    VALIDATE (BYTE (^FILE.PATH^ [F.PATH.SIZE - 1]), %C) /= 0]
@BOX 8.1
-8 => PW0;
@BOX 9.1
IF CHECK.REMOTE (U.NAME) => REMOTE.DIR.NO >= 0
@BOX 10.1
FILE.PATH => ADDRESS OF STRING.PARAMS [0];
REMOTE.FILE.REQUEST (REMOTE.DIR.NO, %80,
      ^STRING.PARAMS, NIL.L64, NIL.INT);
@END

@TITLE SYSCMD16.10(3,11)

@COL 1S-2R-3R-4T-5T-6R-7F

@FLOW 1-2-3-4YES-5OK-6-7
@FLOW 4NO-7
@FLOW 5FAIL-7


@BOX 1.0
START FILE REQUEST (FILE PATH, USER NAME, ACCESS)
@BOX 2.0
CHECK IN
[SYS01]
@BOX3.0
GET DIRECTORY PATH
(PRECEDING THE FILE NAME)
AND FILE NAME
#SYSCMD16.10.2
@BOX 4.0
IS DIRECTORY PATH VALID?
@BOX 5.0
FIND USER IDENTIFICATION
OF FILE OWNER
@BOX 6.0
CHECK ACCESS PERMISSION
#SYSCMD16.10.1
@BOX 7.0
END
@BOX 1.1
PROC START.FILE.REQUEST (FILE.PATH, U.NAME, ACC);
INTEGER REQ.UID, CURR.UID, SUPERIOR, FILE.START;
ADDR [LOGICAL8] DIR.PATH, F.NAME;
@BOX 2.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.IN, 0, 0);
@BOX 3.1
::GET DIR PATH
#SYSCMD16.10.2
F.NAME => START.FILE.REQUEST;
@BOX 4.1
VALIDATE.PATH (DIR.PATH, U.NAME, 1);
IF PW0 /= 0
@BOX 5.1
IF U.NAME /= 0 THEN
   SYS17.FIND.UID (U.NAME);
   PW1 => REQ.UID;
   PW2 => SUPERIOR;
FI
IF PW0 /= 0
@BOX 6.1
MAKE (FILE.VARS, 0, SYS13.GET.PRB (-1, 16)) => C.FILE.VARS;
USER.ID OF C.FILE.VARS^ => CURR.UID;
IF U.NAME /= 0 AND CURR.UID /= REQ.UID AND SUPERIOR < 0 THEN
   ::CHECK ACCESS
   #SYSCMD16.10.1
FI
@BOX 7.1
END
@END




@TITLE SYSCMD16.10.1(3,11)

@COL 1S-2R-5T-6T-8T-9F
@COL 7R

@ROW 6-7

@FLOW 1-2-5FOUND-6THIS USER-8-9
@FLOW 5AT END-7-9
@FLOW 6-5
@FLOW 8YES-5

@BOX 1.0
CHECK ACCESS
@BOX 2.0
SET POINTER TO
PERMIT ENTRIES
@BOX 4.0
GET FILE NAME
@BOX 5.0
SEARCH PERMIT ENTRIES FOR
REQUIRED FILE NAME
@BOX6.0
ENTRY NOT FOR THIS USER?
@BOX 7.0
RETURN FAULT STATUSA -45
(ILLEGAL ACCESS REQUIRED)
@BOX 8.0
REQUIRED ACCESS NOT GRANTED?
@BOX 9.0
END
@BOX 1.1
CHECK.ACCESS:BEGIN
INTEGER COUNT, PTR, UID, I;
@BOX 2.1
SELECT DIR.0^;
NO.OF.FILES.PERMITTED => COUNT;
-1 => PTR;
@BOX 5.1
WHILE 1 +> PTR < COUNT AND
   COMPARE.NAME (%"ALL", ^PERMIT.FNAME OF PERMISSIONS^ [PTR]) /= 0 AND
   COMPARE.NAME (F.NAME, ^PERMIT.FNAME OF PERMISSIONS^ [PTR]) /= 0 DO OD
IF PTR = COUNT
@BOX 6.1
SELECT PERMISSIONS^ [PTR];
-1 => I;
WHILE 1 +> I < MAX.PERMITTED.USERS AND
      PERMITTED.USERS [I] => UID /= 0 AND
      UID - 1 /= CURR.UID DO OD
IF I = MAX.PERMITTED.USERS
@BOX 7.1
-45 => PW0;
@BOX 8.1
IF ACCESSES [I] & ACC /= ACC
@BOX 9.1
END
@END


@TITLE SYSCMD16.10.2(3,11)

@COL 1S-2T-3R-4R-5F

@FLOW 1-2YES-3-4-5
@FLOW 2NO-4

@BOX 1.0
GET DIR PATH
@BOX 2.0
IS FILE PATH SPECIFIED?
@BOX 3.0
FIND SIZE OF DIR PATH
@BOX 4.0
GET DIRECTORY PATH
(PRECEDIND FILE NAME)
AND FILE NAME
@BOX 5.0
END
@BOX 1.1
::GET.DIR.PATH
BEGIN
INTEGER I, J, MAXCH, FLAG;
0 => FLAG => FILE.START;
@BOX 2.1
0 => I;
IF SIZE (FILE.PATH) => MAXCH =< 0
@BOX 3.1
FOR J < MAXCH DO
   IF FILE.PATH^ [J] = "/" THEN
      J => I;
      1 => FLAG;
   FI
OD
@BOX 4.1
PART (FILE.PATH, 0, I - 1) => DIR.PATH;
IF FLAG = 1 THEN
   I + 1 => FILE.START;
FI
PART (FILE.PATH, FILE.START, MAXCH - 1) => F.NAME;
@BOX 5.1
END
@END
@TITLE SYSCMD16.11(3,11)

@COL 1S-3R-4F

@FLOW 1-3-4

@BOX 1.0
END FILE REQUEST
@BOX 3.0
CHECKOUT
[SYS01]
@BOX 4.0
END
@BOX 1.1
PROC END.FILE.REQUEST;
@BOX 3.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.OUT, 0, 0);
@BOX 4.1
END
@END



@TITLE SYSCMD16.12(3,11)


@COL 1S-2T-3T-4T-5R-9F
@COL 10N-11N-6R-7R-8R

@ROW 2-10
@ROW 3-11
@ROW 5-6
@ROW 9-7

@FLOW 1-2OK-3OK-4OK-5-9
@FLOW 2FAIL-10-8-9
@FLOW 3FAIL-11-7-8
@FLOW 4FAIL-6-7

@BOX 1.0
SECURE DIR
@BOX 2.0
ALLOCATE NEW DISC BLOCK
FOR COPY OF DIRECTORY
@BOX 3.0
ENTER INTERRUPT LEVEL TO
SECURE COPY OF THE DIRECTORY
@BOX 4.0
UPDATE AND SECURE
USER MASTER BLOCK
@BOX 5.0
RELEASE DISC SPACE OCCUPIED
BY PREVIOUS COPY OF DIRECTORY
@BOX 6.0
RESET USER MASTER BLOCK
@BOX 7.0
RELEASE DISC SPACE FOR
THE NEW COPY OF THE
DIRECTORY
@BOX 8.0
RETURN FAULT STATUS -49
(DISC TRANSFER FAILED)
@BOX 9.0
END
@BOX 1.1
PROC SECURE.DIR;
INTEGER DIR.ID;
@BOX 2.1
CURRENT.DIR.ADDR => OLD.DIR.ADDR;
SYS03.ALLOCATE.DRUM.BLOCK () => CURRENT.DIR.ADDR => FILE.TRANSFER.ADDR;
IF PW0 /= 0
@BOX 3.1
SYS13.ENTER.INT.LEVEL (^FILE.TRANSFER, 1, 2);
IF FILE.TRANSFER.STATUS /= 0
@BOX 4.1
CURRENT.DIR.ID - ((CURRENT.DIR.ID / NO.OF.DIRS) * NO.OF.DIRS) => DIR.ID;
SELECT USER.MB.TABLE [DIR.ID] OF USER.MB^;
CURRENT.DIR.ADDR => DIR.DISC.ADDR;
CURRENT.DIR.SIZE => DIR.SIZE;
SECURE.USER.MB ();
IF PW0 /= 0
@BOX 5.1
IF OLD.DIR.SIZE /= 0 THEN
   SYS03.RELEASE.DRUM.BLOCK (OLD.DIR.ADDR);
FI
@BOX 6.1
OLD.DIR.ADDR => DIR.DISC.ADDR;
OLD.DIR.SIZE => DIR.SIZE;
@BOX 7.1
SYS03.RELEASE.DRUM.BLOCK (CURRENT.DIR.ADDR);
@BOX 8.1
-49 => PW0;
@BOX 9.1
END
@END

@TITLE SYSCMD16.13(3,11)

@COL 1S-2T-3R-6R-4F
@COL 5R

@ROW 3-5

@FLOW 1-2FOUND-3-6-4
@FLOW 2NOT FOUND-5-4

@BOX 1.0
FIND FILE ENTRY (FILENAME)
@BOX 2.0
SEARCH DIRECTORY FOR
REQUIRED FILENAME
@BOX 3.0
RETURN INDEX OF FILE
INTO DIRECTORY
@BOX 4.0
END
@BOX 5.0
RETURN FAULT STATUS -43
(FILE/DIRECTORY NAME DOES NOT EXIST)
@BOX 6.0
RETURN INDEX INTO SFT
IF FILE OPEN
@BOX 1.1
PROC FIND.FILE.ENTRY (F.NAME);
INTEGER COUNT, SFN, FILE.NO, FILE.IDENTITY;
@BOX 2.1
NO.OF.FILES OF DIR.0^ => COUNT;
-1 => FILE.NO;
WHILE 1 +> FILE.NO < COUNT AND
   COMPARE.NAME (F.NAME, ^FILE.NAME OF DIR^ [FILE.NO]) /= 0 DO OD
IF FILE.NO = COUNT
@BOX 3.1
FILE.NO => FIND.FILE.ENTRY;
FILE.ID OF DIR^ [FILE.NO] => FILE.IDENTITY;
@BOX 4.1
END
@BOX 5.1
-43 => PW0 => FIND.FILE.ENTRY;
@BOX 6.1
-1 => SFN;
WHILE 1 +> SFN < SYS14.NO.OF.SYS.SEGS AND
   FILE.IDENTITY /= FILE.IDENT OF SFT [SFN] DO OD
IF SFN => PW1 = SYS14.NO.OF.SYS.SEGS THEN
   -1 => PW1;
FI
@END


@TITLE SYSCMD16.14(3,11)

@COL 1S-2T-3R-4R-5F
@COL 6R

@ROW 3-6

@FLOW 1-2NO-3-4-5
@FLOW 2YES-6-5

@BOX 1.0
ALLOCATE FILE ENTRY
@BOX 2.0
FILE LIMIT EXCEEDED?
@BOX 3.0
ALLOCATE NEW DIRECTORY ENTRY
AND UPDATE USER MASTER BLOCK
@BOX 4.0
COMPUTE NEW SIZE OF DIRECTORY
@BOX 5.0
END
@BOX 6.0
RETURN FAULT STATUS -41
(FILE LIMIT EXCEEDED)
@BOX 1.1
PROC ALLOCATE.FILE.ENTRY;
@BOX 2.1
SELECT DIR.0^;
IF TOTAL.NO.OF.FILES OF USER.MB^
    >= SYS17.GET.USER.PARAM (CURRENT.UMB.ID, SYS17.NO.OF.FILES) OR
   TOTAL.FILE.SPACE OF USER.MB^ >=
    SYS17.GET.USER.PARAM (CURRENT.UMB.ID, SYS17.FILE.STORE) OR
   2 + NO.OF.FILES.PERMITTED + NO.OF.FILES >= MAX.DIR.ENTRY
@BOX 3.1
NO.OF.FILES => ALLOCATE.FILE.ENTRY;
1 +> NO.OF.FILES;
1 +> TOTAL.NO.OF.FILES OF USER.MB^;
MAKE (DIR.ENTRY, NO.OF.FILES, 2 + NO.OF.FILES.PERMITTED * DIR.ENTRY.SIZE +
      DIR.SEG.ADDR + FILE.SEG.ADDR) => DIR;
@BOX 4.1
CURRENT.DIR.SIZE => OLD.DIR.SIZE;
NO.OF.FILES.PERMITTED + NO.OF.FILES + 2 * DIR.ENTRY.SIZE
   + SYS14.PAGE.SIZE - 1 ->> SYS14.PAGE.SHIFT => CURRENT.DIR.SIZE;
@BOX 5.1
END
@BOX 6.1
-41 => PW0 => ALLOCATE.FILE.ENTRY;
@END


@TITLE SYSCMD16.15(3,11)

@COL 1S-2R-3R-4F

@FLOW 1-2-3-4

@BOX 1.0
DELETE FILE ENTRY (FILE NO)
@BOX 2.0
RECOVER ENTRY IN
FILE DIRECTORY
@BO 3.0
COMPUTE NEW SIZE
OF DIRECTORY
@BOX 4.0
END
@BOX 1.1
PROC DELETE.FILE.ENTRY (FILE.NO);
INTEGER COUNT;
ADDR DIR.ENTRY DIR.TEMP1, DIR.TEMP2;
@BOX 2.1
SELECT DIR.0^;
1 -> NO.OF.FILES => COUNT;
1 -> TOTAL.NO.OF.FILES OF USER.MB^;
WHILE FILE.NO < COUNT DO
::   DIR^ [FILE.NO + 1] => DIR^ [FILE.NO];
   ^DIR^ [FILE.NO + 1] => DIR.TEMP1;
   ^DIR^ [FILE.NO] => DIR.TEMP2;
   DIR.TEMP1^ => DIR.TEMP2^;
   1 +> FILE.NO;
OD
@BOX 3.1
CURRENT.DIR.SIZE => OLD.DIR.SIZE;
NO.OF.FILES.PERMITTED + NO.OF.FILES + 2 * DIR.ENTRY.SIZE
   + SYS14.PAGE.SIZE - 1 ->> SYS14.PAGE.SHIFT => CURRENT.DIR.SIZE;
@BOX 4.1
END
@END


@TITLE SYSCMD16.16(3,11)

@COL 1S-5R-6F

@FLOW 1-5-6

@BOX 1.0
CLOSE FILE
@BOX 5.0
NOTE FILE CLOSED
@BOX 6.0
END
@BOX 1.1
PROC CLOSE.FILE (SSN);
@BOX 5.1
0 => FILE.IDENT OF SFT [SSN]
  => COUNT OF SFT [SSN];
@BOX 6.1
END
@END


@TITLE SYSCMD16.17(3,11)

@COL 1S-2R-3F

@FLOW 1-2-3

@BOX 1.0
INIT FILES (FILE VARS, UID)
@BOX 2.0
INITIALISE FILE VARIABLES
IN SPECIFIED PRB
@BOX 3.0
END
@BOX 1.1
PROC INIT.FILES (FILE.VARS, UID);
INTEGER I;
SELECT FILE.VARS^;
@BOX 2.1
0 => DIR.ID;
UID => USER.ID;
FOR I < NO.OF.REMOTE.DIRS DO
   -1 => REMOTE.TABLE [I];
OD
@BOX 3.1
END
@END


@TITLE SYSCMD16.18(3,11)

@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
TINI FILES (SPN)
@BOX 2.0
RESET REMOTE DEFINITION
@BOX 3.0
END
@BOX 1.1
PROC TINI.FILES (SPN);
INTEGER I, J;
ADDR FILE.VARS C.FILE.VARS;
MAKE (FILE.VARS, 0, SYS13.GET.PRB (SPN, 16)) => C.FILE.VARS;
SELECT C.FILE.VARS^;
@BOX 2.1
FOR I < NO.OF.REMOTE.DIRS DO
   IF REMOTE.TABLE [I] => J >= 0 THEN
      REMOTE.FILE.REQUEST (J, %F, NIL.ADDR, NIL.L64, NIL.INT);
      REMOTE.FREE => REMOTE.LINK OF REMOTE.DIRS [J];
      J => REMOTE.FREE;
   FI
OD
@BOX 3.1
END
@END


@TITLE SYSCMD16.19(3,11)

@COL 1S-26T-23T-25T-2T-28T-31T-3R-4T-5T-6R-13T-7R-8R-10R-15N-11F
@COL 27R-24R-30R-29R-12T-18R-19N-16N

@ROW 2-30
@ROW 3-29
@ROW 5-12
@ROW 7-18
@ROW 10-19
@ROW 15-16
@ROW 23-27
@ROW 25-24

@FLOW 1-26OK-23LOCAL-25CURRENT USER-2OK-28NO-31NO-3-4FOUND-5THIS USER-6-13NO-7-8
-10-15-11
@FLOW 4AT END-12NO SPACE-18-19-10
@FLOW 5-4
@FLOW 26INVALID-27-16-15
@FLOW 25NO-30-16
@FLOW 23REMOTE-24-16-15
@FLOW 2FAIL-10
@FLOW 12YES-6
@FLOW 13YES-10
@FLOW 28YES-29-19
@FLOW 31INVALID USER-19

@BOX 1.0
PERMIT (FILEPATH, PERMITTED USER, ACCESS, USERNAME)
@BOX 2.0
START FILE REQUEST
[SYSCMD16.10]
@BOX 3.0
SET POINTERS TO PERMISSION &
DIRETORY ENTRIES
@BOX 4.0
SEARCH PERMIT ENTRIES
FOR REQUIRED FILENAME
@BOX 5.0
ENTRY NOT FOR THIS USER
@BOX 6.0
CHECK ACCESS PERMISSION
GRANTED
@BOX 7.0
UPDATE PERMISSION INFORMATION
#SYSCMD16.19.1
@BOX 8.0
SECURE COPY OF DIRECTORY
ON DISC
[SYSCMD16.12]
@BOX 10.0
END FILE REQUEST
[SYSCMD16.11]
@BOX 11.0
END
@BOX 12.0
IS THERE SPACE FOR
A NEW PERMIT ENTRY?
@BOX 13.0
INVALID ACCESS SPECIFIED?
@BOX 18.0
RETURN FAULT STATUS -49
(DISC TRANSFER FAILED)
@BOX 23.0
IS FILE REMOTE?
[SYSCMD16.24]
@BOX 24.0
ISSUE THE REQUIRED PERMIT
FOR THE REMOTE USER
[SYSCMD16.25]
@BOX 25.0
IS CURRENT USER
GRANTING PERMISSION?
@BOX 26.0
VALIDATE FILE PATH
@BOX 27.0
RETURN FAULT STATUS -8
(VALIDATE FAIL)
@BOX 28.0
DOES FILE NAME INCLUDE
ANY INVALID CHARACTERS?
@BOX 29.0
RETURN FAULT STATUS -48
(INVALID CHARACTER IN
FILE/DIRECTORY NAME)
@BOX 30.0
RETURN FAULT STATUS -25
(USER ERROR)
@BOX 31.0
GET IDENTIFICATION OF USER
RECEIVING THE PERMISSION
@BOX 1.1
PROC PERMIT (FILE.PATH, PERMITTED.USER, ACC, USER.NAME);
INTEGER REMOTE.DIR.NO, PERMITTED.UID, OUTER, INNER, F.PATH.SIZE,
         COUNT, PTR, INDEX, FILE.COUNT, PERMIT.F.COUNT, PERMIT.U.COUNT;
LOGICAL8 CH, REQ.ACCESS;
ADDR [DIR.ENTRY] DIR;
ADDR [PERMIT.TYPE] PERMISSIONS;
ADDR [LOGICAL8] F.NAME;
LOGICAL64 [2] L64.PARAMS;
ADDRESS8 [1] STRING.PARAMS;
PSPEC REMOVE.ACCESS (INTEGER, INTEGER);
#SYSCMD16.19.2
0 => PW0;
@BOX 2.1
START.FILE.REQUEST (FILE.PATH, USER.NAME, 0) => F.NAME;
IF PW0 /= 0
@BOX 3.1
SELECT DIR.0^;
NO.OF.FILES.PERMITTED => PERMIT.F.COUNT;
NO.OF.USERS.PERMITTED => PERMIT.U.COUNT;
NO.OF.FILES => FILE.COUNT;
MAKE (PERMIT.TYPE, PERMIT.F.COUNT + 1, 1 * DIR.ENTRY.SIZE +
      DIR.SEG.ADDR + FILE.SEG.ADDR) => PERMISSIONS;
MAKE (DIR.ENTRY, FILE.COUNT + 2, 1 + PERMIT.F.COUNT *
      DIR.ENTRY.SIZE + DIR.SEG.ADDR + FILE.SEG.ADDR) => DIR;
-1 => OUTER;
@BOX 4.1
-1 => INNER;
WHILE 1 +> OUTER < PERMIT.F.COUNT AND
      COMPARE.NAME (F.NAME, ^PERMIT.FNAME OF PERMISSIONS^ [OUTER]) /= 0 DO OD
IF OUTER = PERMIT.F.COUNT
@BOX 5.1
SELECT PERMISSIONS^ [OUTER];
WHILE 1 +> INNER < MAX.PERMITTED.USERS AND
      PERMITTED.USERS [INNER] /= PERMITTED.UID /= -1 DO OD
IF INNER = MAX.PERMITTED.USERS
@BOX 6.1
0 => REQ.ACCESS;
DATAVEC ACCESS.PERMISSIONS (LOGICAL8)
"X" "W" "R" "E" "C" "U" "D" "N"
END
WHILE ACC /= 0 AND PW0 = 0 DO
   ACC & %FF => CH;
   ACC ->> 8 => ACC;
   -1 => INDEX;
   WHILE 1 +> INDEX < 8 AND CH /= ACCESS.PERMISSIONS [INDEX] DO OD
   IF INDEX < 8 THEN
      1 <<- INDEX !> REQ.ACCESS;
   ELSE
      -45 => PW0;
   FI
OD
@BOX 7.1
::UPDATE PERMISSION INFORMATION
#SYSCMD16.19.1
@BOX 8.1
SECURE.DIR ();
@BOX 10.1
END.FILE.REQUEST ();
@BOX 11.1
END
@BOX 12.1
IF MAX.DIR.ENTRY > 2 +
         FILE.COUNT + PERMIT.F.COUNT
@BOX 13.1
IF PW0 /= 0
@BOX 18.1
-49 => PW0;
@BOX 23.1
IF CHECK.REMOTE (USER.NAME) => REMOTE.DIR.NO >= 0
@BOX 24.1
FILE.PATH => ADDRESS OF STRING.PARAMS [0];
PERMITTED.USER => L64.PARAMS [0];
ACC => L64.PARAMS [1];
REMOTE.FILE.REQUEST (REMOTE.DIR.NO, %60,
   ^STRING.PARAMS, ^L64.PARAMS, NIL.INT);
@BOX 25.1
NAMES();
IF USER.NAME /= 0 /= PWW1
@BOX 26.1
IF SIZE (FILE.PATH) => F.PATH.SIZE /= 0 AND
   [VALIDATE (BYTE (^FILE.PATH^ [0]), %C) /= 0 OR
    VALIDATE (BYTE (^FILE.PATH^ [F.PATH.SIZE - 1]), %C) /= 0]
@BOX 27.1
-8 =>PW0;
@BOX 28.1
IF CHECK.NAME (F.NAME) /= 0
@BOX 29.1
-48 => PW0;
@BOX 30.1
-25 => PW0;
@BOX 31.1
IF PERMITTED.USER = "ALL" THEN
  0 => PERMITTED.UID;
ELSE
   SYS17.FIND.UID (PERMITTED.USER);
   PW1 + 1 => PERMITTED.UID;
FI
IF PW0 /= 0
@END


@TITLE SYSCMD16.19.1(3,11)

@COL 1S-2T-3T-5R-6R-7R-8F
@COL 4R

@ROW 5-4

@FLOW 1-2NO-3NO-5-7-8
@FLOW 2YES-4-7
@FLOW 3YES-6-7

@BOX 1.0
BEGIN
@BOX 2.0
NEW PERMIT ENTRY
TO BE CREATED?
@BOX 3.0
EXISTING ACCESS PERMISSION
TO BE REMOVED?
@BOX 4.0
CREATE A NEW
PERMIT ENTRY
@BOX 5.0
UPDATE ACCESS PERMISSION OF
AN EXISTING PERMIT ENTRY
@BOX 6.0
REMOVE ACCESS PERMISSION
AND REARRANGE ENTRIES
@BOX 7.0
UPDATE DIRECTORY
INFORMATION
@BOX 8.0
END
@BOX 1.1
BEGIN
ADDR DIR.ENTRY DIR.TEMP1, DIR.TEMP2;
INTEGER I, FIRST, LAST, SHIFTUP;
SELECT PERMISSIONS^ [OUTER];
@BOX 2.1
IF OUTER = PERMIT.F.COUNT
@BOX 3.1
IF REQ.ACCESS = 0
@BOX 4.1
IF REQ.ACCESS /= 0 THEN
   1 +> PERMIT.F.COUNT;
   1 +> PERMIT.U.COUNT;
   WHILE FILE.COUNT > 0 DO
      ::DIR^ [FILE.COUNT] => DIR^ [FILE.COUNT + 1];
      ^DIR^ [FILE.COUNT] => DIR.TEMP1;
      ^DIR^ [FILE.COUNT + 1] => DIR.TEMP2;
      DIR.TEMP1^ => DIR.TEMP2^;
      1 -> FILE.COUNT;
   OD
   STORE.NAME (F.NAME, ^PERMIT.FNAME);
   PERMITTED.UID => PERMITTED.USERS [0];
   REQ.ACCESS => ACCESSES [0];
   0 => I;
   WHILE 1 +> I < MAX.PERMITTED.USERS DO
      -1 => PERMITTED.USERS [I];
      0 => ACCESSES [I];
   OD
FI
@BOX 5.1
IF PERMITTED.USERS [INNER] = -1 THEN
   1 +> PERMIT.U.COUNT;
FI
PERMITTED.UID => PERMITTED.USERS [INNER];
REQ.ACCESS => ACCESSES [INNER];
@BOX 6.1
0 => SHIFTUP;
IF PERMITTED.USERS [MAX.PERMITTED.USERS - 1] /= -1 THEN
   1 => SHIFTUP
FI
REMOVE.ACCESS (OUTER, INNER);
IF SHIFTUP = 1 THEN
   OUTER => FIRST;
   0 => LAST;
   WHILE 1 +> OUTER < PERMIT.F.COUNT DO
      IF COMPARE.NAME (F.NAME, ^PERMIT.FNAME OF PERMISSIONS^ [OUTER]) = 0 THEN
         OUTER => LAST;
      FI
   OD
   IF LAST > FIRST THEN
      PERMITTED.USERS [0] OF PERMISSIONS^ [LAST] =>
      PERMITTED.USERS [INNER] OF PERMISSIONS^ [FIRST];
      ACCESSES [0] OF PERMISSIONS^ [LAST] =>
      ACCESSES [INNER] OF PERMISSIONS^ [FIRST];
      REMOVE.ACCESS (LAST, 0);
      1 +> PERMIT.U.COUNT;
   FI
FI
@BOX 7.1
SELECT DIR.0^;
PERMIT.F.COUNT => NO.OF.FILES.PERMITTED;
PERMIT.U.COUNT => NO.OF.USERS.PERMITTED;
NO.OF.FILES.PERMITTED + NO.OF.FILES + 2 *
 DIR.ENTRY.SIZE + SYS14.PAGE.SIZE - 1 ->> SYS14.PAGE.SHIFT
 => CURRENT.DIR.SIZE;
@BOX 8.1
END
@END
@TITLE SYSCMD16.19.2(3,11)
@COL 1S-2R-3F

@FLOW 1-2-3

@BOX 1.0
BEGIN
@BOX 2.0
REMOVE ACCESS
PROCEDURE
@BOX 3.0
END
@BOX 1.1
BEGIN
@BOX 2.1
PROC REMOVE.ACCESS (OUTER, INNER);
ADDR DIR.ENTRY DIR.TEMP1, DIR.TEMP2;
ADDR PERMIT.TYPE PERMIT.TEMP1, PERMIT.TEMP2;
INTEGER I;
SELECT PERMISSIONS^ [OUTER];
IF INNER = 0 AND PERMITTED.USERS [INNER + 1] = -1 THEN
   1 -> PERMIT.F.COUNT;
   1 -> PERMIT.U.COUNT;
   WHILE OUTER < PERMIT.F.COUNT DO
      ::PERMISSIONS^ [OUTER + 1] =>
      ::PERMISSIONS^ [OUTER];
      ^PERMISSIONS^ [OUTER + 1] => PERMIT.TEMP1;
      ^PERMISSIONS^ [OUTER] => PERMIT.TEMP2;
      PERMIT.TEMP1^ => PERMIT.TEMP2^;
      1 +> OUTER;
   OD
   FOR I < FILE.COUNT DO
      ::DIR^ [I + 1] => DIR^ [I];
      ^DIR^ [I + 1] => DIR.TEMP1;
      ^DIR^ [I] => DIR.TEMP2;
      DIR.TEMP1^ => DIR.TEMP2^;
   OD
ELSE
   IF INNER /= -1 AND PERMITTED.USERS [INNER] /= -1 THEN
      1 -> PERMIT.U.COUNT;
      WHILE INNER < MAX.PERMITTED.USERS - 1 DO
         PERMITTED.USERS [INNER + 1] => PERMITTED.USERS [INNER];
         ACCESSES [INNER + 1] => ACCESSES [INNER];
         1 +> INNER;
      OD
      -1 => PERMITTED.USERS [INNER];
      0 => ACCESSES [INNER];
   FI
FI
END
@BOX 3.1
END
@END
@TITLE SYSCMD16.20(3,11)

@COL 1S-2T-4T-5T-6R-7R-8F

@FLOW 1-2-4OK-5FAIL-6-7-8
@FLOW 4FAIL-8
@FLOW 5OK-7

@BOX 1.0
GET DIR (NEXT DIR ID)

@BOX 2.0
MAP SYSTEM MASTER BLOCK
@BOX 4.0
GET USER MASTER BLOCK
@BOX 5.0
ENTER INTERRUPT LEVEL TO
RETRIEVE DIRECTORY
@BOX 6.0
RETURN FAULT STATUS -49
(DISC TRANSFER FAILED)
@BOX 7.0
SET POINTER TO DIRECTORY
@BOX 8.0
END
@BOX 1.1
PROC GET.DIR (NEXT.DIR.ID);
INTEGER REQ.DIR, NEXT.UMB.ID;
0 => PW0;
@BOX 2.1
SYS14.CMD.MAP (FILE.SEG, FILE.MAPPED.SEG);
PW6 * SYS14.SEG.SIZE => FILE.SEG.ADDR;
MAKE (SYS.MB.ENTRY, 0, FILE.SEG.ADDR) => SYS.MB;
@BOX 4.1
NEXT.DIR.ID / NO.OF.DIRS => NEXT.UMB.ID;
NEXT.DIR.ID - (NEXT.UMB.ID * NO.OF.DIRS) => REQ.DIR;
GET.USER.MB (NEXT.UMB.ID);
IF PW0 /= 0
@BOX 5.1
NEXT.DIR.ID => CURRENT.DIR.ID;
SELECT USER.MB.TABLE [REQ.DIR] OF USER.MB^;
DIR.DISC.ADDR => CURRENT.DIR.ADDR => FILE.TRANSFER.ADDR;
DIR.SIZE => CURRENT.DIR.SIZE;
SYS13.ENTER.INT.LEVEL (^FILE.TRANSFER, 0, 2);
IF FILE.TRANSFER.STATUS = 0
@BOX 6.1
-1 => CURRENT.DIR.ID;
-49 => PW0;
@BOX 7.1
MAKE (DIR.ENTRY, 0, DIR.SEG.ADDR + FILE.SEG.ADDR ) => DIR.0;
MAKE (PERMIT.TYPE, NO.OF.FILES.PERMITTED OF DIR.0^, 1 * DIR.ENTRY.SIZE +
      DIR.SEG.ADDR + FILE.SEG.ADDR) => PERMISSIONS;
MAKE (DIR.ENTRY, NO.OF.FILES OF DIR.0^, 2 + NO.OF.FILES.PERMITTED OF DIR.0^ *
      DIR.ENTRY.SIZE + DIR.SEG.ADDR + FILE.SEG.ADDR) => DIR;
@BOX 8.1
END
@END
@TITLE SYSCMD16.21(3,11)

@COL 1S-2R-3F

@FLOW 1-2-3

@BOX 1.0
GET SYS MB (VERSION)
@BOX 2.0
ENTER INTERRUPT LEVEL TO
READ SPECIFIED MASTER BLOCK
@BOX 3.0
END
@BOX 1.1
PROC GET.SYS.MB (VERSION);
@BOX 2.1
SYS.MB.START.ADDR  -= VERSION => FILE.TRANSFER.ADDR
   => CURRENT.SYS.MB.ADDR;
SYS13.ENTER.INT.LEVEL (^FILE.TRANSFER, 0, 0);
IF FILE.TRANSFER.STATUS /= 0 THEN
   -49 =>PW0;
FI
@BOX 3.1
END
@END


@TITLE SYSCMD16.22(3,11)

@COL 1S-13T-2T-3R-4T-5T-6T-7T-8R-11R-12N-16F
@COL 14R-10R-15N

@ROW 2-14
@ROW 3-10
@ROW 12-15

@FLOW 1-13OK-2-3-4YES-5NO-6OK-7OK-8-11-12-16
@FLOW 2REMOTE-10-15-12
@FLOW 4NO-11-12
@FLOW 5YES-11
@FLOW 6-11
@FLOW 7FAIL-11
@FLOW 13INVALID-14-15

@BOX 1.0
CATALOGUE PERMIT (DIR PATH, USER NAME)
@BOX 2.0
IS DIRECTORY REMOTE
[SYSCMD16.24]
@BOX 3.0
CHECK IN
[SYS01]
@BOX 4.0
IS LOCAL DIRECTORY
NAME VALID
@BOX 5.0
NO PERMIT ENTRY
@BOX 6.0
CREATE A SEGMENT
FOR PERMIT ENTRIES
@BOX 7.0
GET UID OF USER
WHOSE PERMIT ENTRIES
ARE TO BE CATALOGUED
@BOX 8.0
COPY PERMIT ENTRIES FOR
THIS USER TO SEGMENT
@BOX 10.0
CATALOGUE PERMIT ENTRIES
OF REMOTE DIRECTORY
@BOX 11.0
CHECK OUT
[SYS01]
@BOX 13.0
VALIDATE DIRECTORY PATH
@BOX 14.0
RETURN FAULT STATUS -8
(VALIDATE FAIL)
@BOX 16.0
END
@BOX 1.1
PROC CATALOGUE.PERMIT (DIR.PATH, U.NAME);
INTEGER SEG.NO, SEG.COUNT, REMOTE.DIR.NO,
        D.PATH.SIZE, REQ.UID, CURR.UID, SUPERIOR;
ADDR [DISPLAY.PERMIT.ENTRY] PERMIT.COPY;
ADDRESS8 [1] STRING.PARAMS;
0 => PW0;
@BOX 2.1
IF CHECK.REMOTE (U.NAME) => REMOTE.DIR.NO >= 0
@BOX 3.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.IN, 0, 0);
@BOX 4.1
VALIDATE.PATH (DIR.PATH, U.NAME, 1);
IF PW0 /= 0
@BOX 5.1
0 => PW1 => PW2;
SELECT DIR.0^;
IF NO.OF.FILES.PERMITTED = 0
@BOX 6.1
CREATE.SEGMENT (-1, NO.OF.USERS.PERMITTED * 25);
PW1 => SEG.NO;
IF PW0 /= 0
@BOX 7.1
SYS14.CMD.MAP (SEG.NO, PERMIT.MAPPED.SEG);
MAKE (DISPLAY.PERMIT.ENTRY, NO.OF.USERS.PERMITTED,
      PW6 * SYS14.SEG.SIZE) => PERMIT.COPY;
MAKE (FILE.VARS, 0, SYS13.GET.PRB (-1, 16)) => C.FILE.VARS;
USER.ID OF C.FILE.VARS^ => CURR.UID => REQ.UID;
IF U.NAME /= 0 THEN
   SYS17.FIND.UID (U.NAME);
   PW1 => REQ.UID;
   PW2 => SUPERIOR;
FI
IF PW0 /= 0
@BOX 8.1
0 => SEG.COUNT;
::COPY RELEVANT ENTRIES
#SYSCMD16.22.1
SEG.COUNT => PW1;
SEG.NO => PW2;
@BOX 10.1
DIR.PATH => ADDRESS OF STRING.PARAMS [0];
REMOTE.FILE.REQUEST (REMOTE.DIR.NO, %70,
        ^STRING.PARAMS, NIL.L64, NIL.INT);
@BOX 11.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.OUT, 0, 0);
@BOX 13.1
IF SIZE (DIR.PATH) => D.PATH.SIZE /= 0 AND
   [VALIDATE (BYTE (^DIR.PATH^ [0]), %C) /= 0 OR
    VALIDATE (BYTE (^DIR.PATH^ [D.PATH.SIZE - 1]), %C) /= 0]
@BOX 14.1
-8 => PW0;
@BOX 16.1
END
@END

@TITLE SYSCMD16.22.1(3,11)

@COL 1S-2R-4R-5F

@FLOW 1-2-4-5

@BOX 1.0
BEGIN
@BOX 2.0
CHECK WHETHER ALL ENTRIES
CAN BE CATALOGUED OR NOT
@BOX 4.0
CATALOGUE PERMIT ENTRIES
RELEVANT TO THIS USER
@BOX 5.0
END
@BOX 1.1
BEGIN
INTEGER UID, I, J, K, FLAG;
0 => FLAG;
@BOX 2.1
IF U.NAME = 0 OR REQ.UID = CURR.UID OR SUPERIOR >= 0 THEN
   1 => FLAG;
FI
@BOX 4.1
FOR I < NO.OF.FILES.PERMITTED DO
   SELECT PERMISSIONS^ [I];
   -1 => J;
   WHILE 1 +> J < MAX.PERMITTED.USERS AND
         PERMITTED.USERS [J] => UID /= -1 DO
      IF [FLAG = 1] OR [UID = 0 OR UID - 1 = CURR.UID] THEN
         SELECT PERMIT.COPY^ [SEG.COUNT];
         FOR K < 16 DO
            PERMIT.FNAME [K] => F.NAME [K];
         OD
         IF UID = 0 THEN
            "ALL" => USER;
         ELSE
            SYS17.FIND.NAMES (UID - 1);
            PWW1 => USER;
         FI
         ACCESSES [J] => ACCESS;
         1 +> SEG.COUNT;
      FI
   OD
OD
@BOX 5.1
END
@END
@TITLE SYSCMD16.23(3,11)

@COL 1S-15T-2R-3T-5R-6T-8R-11R-7T-17N-12F
@COL 16R-10R-18R-19R-20R-14N

@ROW 2-16
@ROW 8-10
@ROW 12-19
@ROW 17-18

@FLOW 1-15OK-2-3-5-6FOUND-8-11-7OK-17-12
@FLOW 15INVALID-16-14-12
@FLOW 3FAIL-12
@FLOW 6NONE-10-20-12
@FLOW 7FAIL-18-19-20


@BOX 1.0
NAME DIR (NEW NAME, FILMAN, MACHINE, INITIAL INFORMATION)
@BOX 2.0
SET DEFAULT FILE MANAGER IF REQUIRED
@BOX 3.0
GET SPN & PID OF
REQUIRED FILE MANAGER
@BOX 5.0
CHECK IN
[SYS01]
@BOX 6.0
SEARCH FOR AN USABLE ENTRY
IN REMOTE DIRECTORY TABLE
@BOX 7.0
GET SHORT IDENTIFICATION
OF THE REMOTE DIR (VIA THE
SPECIFIED FILMAN)
@BOX 8.0
MAKE AN ENTRY FOR CURRENT
PROCESS IN THE REMOTE DIR TABLE
@BOX 10.0
RETUIRN FAULT STATUS -56
(TOO MANY DEFINITIONS)
@BOX 11.0
CHECK OUT
[SYS01]
@BOX 12.0
END
@BOX 15.0
VALIDATE INITIAL INFORMATION
@BOX 16.0
RETURN FAULT STATUS -8
(VALIDATE FAIL)
@BOX 18.0
CHECK IN
[SYS01]
@BOX 19.0
RELEASE REMOTE DIRECTORY
TABLE ENTRY
@BOX 20.0
CHECK OUT
[SYS01]
@BOX 1.1
PROC NAME.DIR (NEWNAME, FILMAN, MACHINE, INITIAL.INFO);
INTEGER I, J, INFO.SIZE, SPN, PID;
ADDR FILE.VARS C.FILE.VARS;
ADDRESS8 [1] STRING.PARAMS;
0 => PW0;
@BOX 2.1
IF FILMAN = 0 THEN
   "FILMAN" => FILMAN
FI
@BOX 3.1
LOOK.UP.PROCESS (FILMAN, MACHINE);
PW1 => SPN;
PW2 => PID;
IF PW0 /= 0
@BOX 5.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.IN, 0, 0);
@BOC 6.1
MAKE (FILE.VARS, 0, SYS13.GET.PRB (-1, 16)) => C.FILE.VARS;
SELECT C.FILE.VARS^;
-1 => I;
WHILE 1 +> I < NO.OF.REMOTE.DIRS AND
      REMOTE.TABLE [I] => J >= 0 AND
      N.NAME OF REMOTE.DIRS [J] /= NEW.NAME DO OD
IF I = NO.OF.REMOTE.DIRS OR [J < 0 AND REMOTE.FREE < 0]
@BOX 7.1
INITIAL.INFO => ADDRESS OF STRING.PARAMS [0];
REMOTE.FILE.REQUEST (J, 1, ^STRING.PARAMS, NIL.L64, NIL.INT);
PW1 => SHORT.ID;
IF PW0 /= 0
@BOX 8.1
IF J < 0 THEN
   REMOTE.FREE => REMOTE.TABLE [I] => J;
   REMOTE.LINK OF REMOTE.DIRS [J] => REMOTE.FREE;
FI
SELECT REMOTE.DIRS [J];
NEW.NAME => N.NAME;
FILMAN => FILMAN.NAME;
MACHINE => MACHINE.NAME;
SPN => DEST [0];
PID => DEST [1];
%8 => DEST [2];
0 => DEST [3];
@BOX 10.1
-56 => PW0;
@BOX 11.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.OUT, 0, 0);
@BOX 12.1
END
@BOX 15.1
IF SIZE (INITIAL.INFO) => INFO.SIZE /= 0 AND
   [VALIDATE (BYTE (^INITIAL.INFO^ [0]), %C) /= 0 OR
    VALIDATE (BYTE (^INITIAL.INFO^ [INFO.SIZE - 1]), %C) /= 0]
@BOX 16.1
-8 => PW0;
@BOX 18.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.IN, 0, 0);
@BOX 19.1
-1 => REMOTE.TABLE [I];
REMOTE.FREE => REMOTE.LINK OF REMOTE.DIRS [J];
J => REMOTE.FREE;
@BOX 20.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.OUT, 0, 0);
@END
@TITLE SYSCMD16.24(3,11)

@COL 1S-9T-12T-13R-20N-5F
@COL 17R-21N

@ROW 13-17
@ROW 20-21

@FLOW 1-9SPECIFIED-12YES-13-20-5
@FLOW 9YES-17-21-20
@FLOW 12NO-17-21
@BOX 1.0
CHECK REMOTE (NAME)
@BOX 5.0
END
@BOX 9.0
IS NAME UNSPECIFIED?
@BOX 12.0
IS NAME PREVIOUSLY DECLARED
IN A NAME DIR COMMAND?
@BOX 13.0
NOTE THE INDEX OF THE
REMOTE DEFINITION
@BOX 17.0
NOTE NOT REMOTE
@BOX 1.1
PROC CHECK.REMOTE (NAME);
INTEGER I, J;
ADDR FILE.VARS C.FILE.VARS;
MAKE (FILE.VARS, 0, SYS13.GET.PRB (-1, 16)) => C.FILE.VARS;
SELECT C.FILE.VARS^;
@BOX 5.1
END
@BOX 9.1
IF NAME = 0
@BOX 12.1
-1 => I;
WHILE 1 +> I < NO.OF.REMOTE.DIRS AND
   REMOTE.TABLE [I] => J >= 0 AND
   N.NAME OF REMOTE.DIRS [J] /= NAME DO OD
IF I = NO.OF.REMOTE.DIRS OR J < 0
@BOX 13.1
J => CHECK.REMOTE;
I => PW1;
@BOX 17.1
-1 => CHECK.REMOTE;
@END
@TITLE SYSCMD16.25(3,11)

@COL 1S-25R-4R-22R-23T-15N-16T-24T-6R-7T-17R-11F
@COL 20N-21N-12T-13R
@ROW 15-20
@ROW 16-21
@FLOW 1-25-4-22-23OK-15-16O.K.-24NO-6-7YES-17-11
@FLOW 16FAIL-21-12-13-20-15
@FLOW 12-11
@FLOW 7NO-11
@FLOW 23BUFFER OVERFLOW-11
@FLOW 24YES-11
@BOX 1.0
REMOTE FILE REQUEST (CMD INDEX, L08 PARAMS, L64 PARAMS, INTEGER PARAMS)
@BOX 4.0
DISCARD ANY MESSAGE ON CHANNEL 7
DEDICATE CHANNEL 7 FOR REPLY
@BOX 5.0
PREPARE THE
MESSAGE BUFFER
@BOX 6.0
WAIT FOR REPLY
@BOX 7.0
READ REPLY OK?
@BOX 11.0
END
@BOX 12.0
IDENTIFY THE NEW
"FILMAN" PROCESS
@BOX 13.0
RECORD THE NEW
SPN AND PID
@BOX 16.0
SEND MESSAGE TO THE
FILE MANAGER OF THE
SPECIFIED MACHINE
@BOX 17.0
LOAD REMOTE PW'S & PWW'S
@BOX 22.0
PREPARE PREAMBLE OF MESSAGE
@BOX 23.0
LOAD INFO FOR INDIVIDUAL
COMMANDS INTO MESSAGE BUFFER
#SYSCMD16.25.1
@BOX 24.0
NO REPLY REQUIRED?
@BOX 25.0
CLEAR THE MESSAGE BUFFER
@BOX 1.1
PROC REMOTE.FILE.REQUEST (REMOTE.DIR.NO, CMD.INDEX, STRING.PARAMS, L64.PARAMS, I
NT.PARAMS);
INTEGER RECEIVE.SEG, OUT.SEG, OUT.SEG.ACC, I, J, K, SEG.NUMBER, SEG.STATUS, MESS
.SIZE;
ADDR SEG.SIZE;
INTEGER [4] DESTIN;
LOGICAL8 [80] MESS;
@BOX 4.1
SELECT REMOTE.DIRS [REMOTE.DIR.NO];
1 +> DEST [3];
SET.CH.STATUS (7, 6, DEST [1], DEST [3]);
WHILE PW0 = 0 DO
   READ.MESSAGE (^MESS, ^DESTIN, 7, -1);
   IF PW0 = 0 AND PW1 /= 0 THEN
      RELEASE.SEGMENT (PW1);
   FI
OD
0 => PW0;
@BOX 6.1
WAIT (%80, 12000);
@BOX 7.1
READ.MESSAGE (^MESS, ^DESTIN, 7, RECEIVE.SEG);
IF PW0 /= 0
@BOX 11.1
END
@BOX 12.1
LOOK.UP.PROCESS (FILMAN.NAME, MACHINE.NAME);
IF PW0 /= 0
@BOX 13.1
PW1 => DEST [0];
PW2 => DEST [1];
SET.CH.STATUS (7, 6, DEST [1], DEST [3]);
@BOX 16.1
FOR I < 4 DO
   DEST [I] => DESTIN [I];
OD
SEND.MESSAGE (^MESS, ^DESTIN, %F,
               DEST [3], OUT.SEG, OUT.SEG.ACC);
IF PW0 /= 0
@BOX 17.1
PW1 => SEG.NUMBER;
PW2 => SEG.SIZE;
PW3 => SEG.STATUS;
FOR J < 4 DO
   PW0 <<- 8 ! MESS [9 - J] => PW0;
   PW1 <<- 8 ! MESS [13 - J] => PW1;
   PW2 <<- 8 ! MESS [17 - J] => PW2;
   PW3 <<- 8 ! MESS [21 - J] => PW3;
   PW4 <<- 8 ! MESS [25 - J] => PW4;
   PW5 <<- 8 ! MESS [29 - J] => PW5;
   PW6 <<- 8 ! MESS [33 - J] => PW6;
OD
FOR J < 8 DO
   PWW1 <<- 8 ! MESS [41 - J] => PWW1;
   PWW2 <<- 8 ! MESS [49 - J] => PWW2;
   PWW3 <<- 8 ! MESS [57 - J] => PWW3;
   PWW4 <<- 8 ! MESS [65 - J] => PWW4;
OD
IF CMD.INDEX = %10 THEN
   ::OPEN.FILE
   SEG.NUMBER => PW1;
   SEG.SIZE => PW2;
   SEG.STATUS => PW3;
ELSE
   IF CMD.INDEX = %50 THEN
   ::CATALOGUE.FILES
      SEG.NUMBER => PW3;
   ELSE
      IF CMD.INDEX = %70 THEN
         ::CATALOGUE.PERMIT
         SEG.NUMBER => PW2;
      FI
   FI
FI
@BOX 22.1
6 => MESS [0];
0 => MESS [2] => MESS [3] => MESS [4]
  => MESS [5];
@BOX 23.1
CMD.INDEX => MESS [6];
IF CMD.INDEX /= 1 THEN
   SHORT.ID => MESS [7]
ELSE
   ::NAME.DIR
   %FF => MESS [7]
FI
::LOAD THE MESSAGE
#SYSCMD16.25.1
MESS.SIZE => MESS [1];
IF PW0 /= 0
@BOX 24.1
IF CMD.INDEX = %F
@BOX 25.1
FOR I < 80 DO
   0 => MESS [I]
OD
-1 => RECEIVE.SEG;
0 => OUT.SEG;
%1E => OUT.SEG.ACC;
@END

@TITLE SYSCMD16.25.1(3,11)

@COL 1S-2R-6F

@FLOW 1-2-6

@BOX 1.0
BEGIN
@BOX 2.0
LOAD PARAMETERS FOR
INDIVIDAL COMMANDS
INTO MESSAGE BUFFER
@BOX 3.0
END
@BOX 1.1
::LOAD THE MESSAGE
BEGIN
LITERAL / INTEGER L64.TYPE = 1, STRING.TYPE = 2, INT.TYPE = 3;
INTEGER MAXCH, MAXCH2, START.POS, I, J, PTR, INDEX;
8 => MESS.SIZE => START.POS;
@BOX 2.1
CMD.INDEX ->> 4 => INDEX;
ALTERNATIVE INDEX FROM
   BEGIN
      ::NAME.DIR & RELEASE.DIR.NAME
   END
   BEGIN
      ::OPEN.FILE
      L64.TYPE => MESS [8];
      0 => J;
      FOR I < 8 DO
         L64.PARAMS^ [0] ->> J => MESS [9 + I];
         8 +> J;
      OD
      INT.PARAMS^ [0] => RECEIVE.SEG;
      17 => START.POS;
      9 +> MESS.SIZE;
   END
   BEGIN
      IF CMD.INDEX = %20 THEN
         ::FILE LOCAL SEG
         INT.PARAMS^ [0] => OUT.SEG;
         READ.SEGMENT.STATUS (OUT.SEG);
         PW2 & %1F => OUT.SEG.ACC;
      ELSE
         ::FILE REMOTE SEG
         INT.TYPE => MESS [8];
         0 => J;
         FOR I < 4 DO
            INT.PARAMS^ [0] ->> J => MESS [9 + I];
            8 +> J;
         OD
         13 => START.POS;
         5 +> MESS.SIZE;
      FI
   END
   BEGIN
      ::DELETE.FILE
   END
   BEGIN
      ::RENAME.FILE
      STRING.TYPE => MESS [8];
      SELECT STRING.PARAMS^ [0];
      SIZE (ADDRESS) => MESS [9] => MAXCH;
      FOR PTR < MAXCH DO
         ADDRESS^ [PTR] => MESS [10 + PTR]
      OD
      STRING.TYPE => MESS [10 +PTR];
      SIZE (ADDRESS OF STRING.PARAMS^ [1]) => MESS [PTR + 11] => MAXCH2;
      12 + PTR => PTR;
      FOR I < MAXCH2 DO
         ADDRESS^ [I] OF STRING.PARAMS^ [1] => MESS [PTR + I]
      OD
      4 + MAXCH + MAXCH2 + MESS.SIZE => MESS.SIZE;
   END
   BEGIN
      ::CATALOGUE.FILES
   END
   BEGIN
      ::PERMIT
      L64.TYPE => MESS [8] => MESS [17];
      0 => J;
      FOR I < 8 DO
         L64.PARAMS^ [0] ->> J => MESS [9 + I];
         L64.PARAMS^ [1] ->> J => MESS [18 + I];
         8 +> J;
      OD
      26 => START.POS;
      18 +> MESS.SIZE;
   END
   BEGIN
      ::CATALOGUE.PERMIT
   END
   BEGIN
      ::READ.FILE.STATUS
   END
   END
IF CMD.INDEX /= %40 /= 2 /= %F THEN
   ::EXCEPT RENAME.FILE & RELEASE.DIR.NAME
   SELECT STRING.PARAMS^ [0];
   STRING.TYPE => MESS [START.POS];
   SIZE (ADDRESS) => MESS [START.POS + 1] => MAXCH;
   2 + START.POS => START.POS;
   IF 80 - START.POS >= MAXCH THEN
      FOR I < MAXCH DO
         ADDRESS^ [I] => MESS [START.POS + I];
      OD
      MAXCH + 2 + MESS.SIZE => MESS.SIZE;
   ELSE
      -39 => PW0;
   FI
FI
@BOX 6.1
END
@END
@TITLE SYSCMD16.26(3,11)
@COL 1S-2R-3T-4R-5R-6F
@FLOW 1-2-3OK-4-5-6
@FLOW 3FAIL-5
@BOX 1.0
DELETE USER DIR (UID)
@BOX 2.0
CHECKIN
[SYS01]
@BOX 3.0
GET DIRECTORY FOR SPECIFIED USER
[SYSCMD16.20]
@BOX 4.0
RETURN FAULT IF USER HAS FILE(S)
@BOX 5.0
CHECKOUT
[SYS01]
@BOX 6.0
END
@BOX 1.1
PROC DELETE.USER.DIR (UID);
@BOX 2.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECKIN, 0, 0);
@BOX 3.1
GET.DIR (UID * NO.OF.DIRS)
IF PW0 /= 0
@BOX 4.1
IF NO.OF.FILES OF DIR.0^ = 0 THEN
   0 => DELETE.USER.DIR;
ELSE
   -1 => DELETE.USER.DIR;
FI
@BOX 5.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECKOUT, 0, 0);
@BOX 6.1
END
@END

@TITLE SYSCMD16.27(3,11)
@COL 1S-2T-3R-4R-5F

@FLOW 1-2NO-3-4-5
@FLOW 2YES-4-5

@BOX 1.0
CHECK NAME (NAME)
@BOX 2.0
NAME HAS NO
CHARACTERS?
@BOX 3.0
CHECK INDIVIDUAL
CHARACTERS
@BOX 4.0
RETURN RESULT
@BOX 5.0
END
@BOX 1.1
PROC CHECK.NAME (NAME);
INTEGER MAXCH, FLAG, I;
LOGICAL8 CH;
0 => FLAG;
@BOX 2.1
IF SIZE (NAME) => MAXCH =< 0
@BOX 3.1
FOR I < MAXCH DO
   IF NAME^ [I] => CH = "/" OR CH = ":"
    OR CH =< " " THEN
      1 => FLAG;
      ->OUT
   FI
OD
OUT:
@BOX 4.1
FLAG => CHECK.NAME;
@BOX 5.1
END
@END
@TITLE SYSCMD16.28(3,11)

@COL 3R
@COL 1S-8T-2T-7R-6F
@COL 9R

@ROW 2-9
@ROW 3-7

@FLOW 1-8OK-2NO-7-6
@FLOW 2-3-6
@FLOW 8INVALID-9-6

@BOX 1.0
CREATE FILE SEGMENT (SEG NO., SEG SIZE, FILEPATH, DIRECTORY NAME)
@BOX 2.0
REMOTE DIRECTORY?
@BOX 3.0
CREATE REMOTE SEGMENT
@BOX 6.0
END
@BOX 7.0
CREATE SEGMENT
@BOX 8.0
VALIDATE FILE PATH
@BOX 9.0
RETURN FAULT STATUS -8
(VALIDATE FAIL)
@BOX 1.1
PROC CREATE.FILE.SEGMENT (SEG.NO, SEG.SIZE, FILE.PATH, DIR.NAME);
INTEGER F.PATH.SIZE, DISC.NO;
0 => PW0;
@BOX 2.1
::IF CHECK.REMOTE (DIR.NAME) >= 0
@BOX 3.1
::REMOTE.FILE.REQUEST (0, ?,
        ::NIL.ADDR, NIL.L64, NILINT);
@BOX 6.1
END
@BOX 7.1
CREATE.SEGMENT (SEG.NO, SEG.SIZE);
@BOX 8.1
IF SIZE (FILE.PATH) => F.PATH.SIZE /= 0 AND
   [VALIDATE (BYTE (^FILE.PATH^ [0]), %C) /= 0 OR
    VALIDATE (BYTE (^FILE.PATH^ [F.PATH.SIZE - 1]), %C) /= 0]
@BOX 9.1
-8 => PW0;
@END
@TITLE SYSCMD16.29(3,11)

@COL 3R
@COL 1S-8T-2T-7R-6F
@COL 9R

@ROW 2-9
@ROW 3-7

@FLOW 1-8OK-2NO-7-6
@FLOW 2-3-6
@FLOW 8INVALID-9-6

@BOX 1.0
CREATE FILE X SEGMENT (SEG SIZE, FILEPATH, DIRECTORY NAME)
@BOX 2.0
REMOTE DIRECTORY?
@BOX 3.0
CREATE REMOTE X SEGMENT
@BOX 6.0
END
@BOX 7.0
CREATE X SEGMENT
@BOX 8.0
VALIDATE FILE PATH
@BOX 9.0
RETURN FAULT STATUS -8
(VALIDATE FAIL)
@BOX 1.1
PROC CREATE.FILE.X.SEGMENT (SEG.SIZE, FILE.PATH, DIR.NAME);
INTEGER F.PATH.SIZE, DISC.NO;
0 => PW0;
@BOX 2.1
::IF CHECK.REMOTE (DIR.NAME) >= 0
@BOX 3.1
::REMOTE.FILE.REQUEST (0, ?,
         ::NIL.ADDR, NIL.L64, NIL.INT);
@BOX 6.1
END
@BOX 7.1
CREATE.X.SEGMENT (SEG.SIZE);
@BOX 8.1
IF SIZE (FILE.PATH) => F.PATH.SIZE /= 0 AND
   [VALIDATE (BYTE (^FILE.PATH^ [0]), %C) /= 0 OR
    VALIDATE (BYTE (^FILE.PATH^ [F.PATH.SIZE - 1]), %C) /= 0]
@BOX 9.1
-8 => PW0;
@END
@TITLE SYSCMD16.30(3,11)

@COL 19R-23R-20R-13R-24R-25N-21N
@COL 1S-17T-22T-18T-2R-4T-5T-6R-7T-8T-9T-14R-15F
@COL 16N-10R-11R-12R

@ROW 19-22
@ROW 23-18
@ROW 24-6
@ROW 25-14
@ROW 20-2
@ROW 21-15
@ROW 13-5
@ROW 8-16
@ROW 14-10
@ROW 15-11

@FLOW 1-17OK-22NO-18NO-2-4NO-5FOUND-6-7OK-8OK-9OK-14-15
@FLOW 17INVALID-19-21-15
@FLOW 22YES-23-21
@FLOW 18YES-20-21
@FLOW 4YES-13-25-14
@FLOW 5NONE-24-25
@FLOW 7FAIL-14
@FLOW 8FAIL-16-11-12-14
@FLOW 9FAIL-10-11

@BOX 1.0
CREATE SUB DIR (DIRECTORY NAME)
@BOX 2.0
CHECK IN
[SYS01]
@BOX 3.0
IS SUBDIRECTORY NAME
SYNTACTICALLY CORRECT?
@BOX 4.0
SUBDIRECTORY ALREADY
EXIST?
@BOX 5.0
FIND A FREE ENTRY IN
USER MASTER BLOCK
@BOX 6.0
CREATE INITIAL EMPTY DIRECTORY
@BOX 7.0
RESERVE SPACE FOR SUBDIRECTORY
ON DISC
@BOX 8.0
SECURE COPY OF SUBDIRECTORY
ON DISC
@BOX 9.0
UPDATE & SECURE USER
MASTER BLOCK
@BOX 10.0
RESET USER MASTER BLOCK
@BOX 11.0
RELEASE DISC SPACE FOR
NEW SUBDIRECTORY
@BOX 12.0
RETURN FAULT STATUS -49
(DISC TRANSFER FAILED)
@BOX 13.0
RETURN FAULT STATUS -47
(FILE/DIRECTORY NAME ALREADY
 EXISTS)
@BOX 14.0
CHECK OUT
[SYS01]
@BOX 15.0
END
@BOX 17.0
VALIDATE DIRECTORY NAME
@BOX 18.0
DOES DIRECTORY NAME INCLUDE
AND INVALID CHARACTERS?
@BOX 19.0
RETURN FAULT STATUS -8
(VALIDATE FAIL)
@BOX 20.0
RETURN FAULT STATUS -48
(INVALID CHARACTER IN
 FILE/DIRECTORY NAME)
@BOX 22.0
IS DIRECTORY NAME
NOT SPECIFIED?
@BOX 23.0
RETURN FAULT STATUS -42
(INVALID DIRECTORY PATH/NAME)
@BOX 24.0
RETURN FAULT STATUS -41
(FILE/DIRECTORY LIMIT EXCEEDED)
@BOX 1.1
PROC CREATE.SUBDIR (D.NAME);
INTEGER FATHER.DIR, SUB.DIR, D.ADDR, D.NAME.SIZE, I, J;
ADDR [LOGICAL8] DIR.PTR;
0 => PW0;
@BOX 2.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.IN, 0, 0);
@BOX 4.1
VALIDATE.PATH (D.NAME, 0, 0);
PW2 => FATHER.DIR;
IF PW0 = 0
@BOX 5.1
0 => PW0;
SELECT USER.MB^;
FOR SUB.DIR < NO.OF.DIRS DO
   IF DIR.SIZE OF USER.MB.TABLE [SUB.DIR] = 0, ->OUT
OD
OUT:IF SUBDIR = NO.OF.DIRS
@BOX 6.1
MAKE (LOGICAL8, SYS14.PAGE.SIZE, DIR.SEG.ADDR + FILE.SEG.ADDR) => DIR.PTR;
FOR I < SYS14.PAGE.SIZE DO
   0 => DIR.PTR^ [I];
OD
1 => CURRENT.DIR.SIZE;
-1 => CURRENT.DIR.ID;
@BOX 7.1
SYS03.ALLOCATE.DRUM.BLOCK () => D.ADDR => FILE.TRANSFER.ADDR;
IF PW0 /= 0
@BOX 8.1
SYS13.ENTER.INT.LEVEL (^FILE.TRANSFER, 1, 2);
IF FILE.TRANSFER.STATUS /= 0
@BOX 9.1
SELECT USER.MB.TABLE [SUB.DIR];
STORE.NAME (D.NAME, ^DIR.NAME);
NEXT.LEVEL OF USER.MB.TABLE [FATHER.DIR] => SAME.LEVEL;
SUB.DIR => NEXT.LEVEL OF USER.MB.TABLE [FATHER.DIR];
-1 => NEXT.LEVEL;
D.ADDR => DIR.DISC.ADDR;
1 => DIR.SIZE;
TIME.AND.DATE ();
PWW1 => CREATE.TIME;
SECURE.USER.MB ();
IF PW0 /= 0
@BOX 10.1
SAME.LEVEL => NEXT.LEVEL OF
 USER.MB.TABLE [FATHER.DIR];
0 => DIR.SIZE;
@BOX 11.1
SYS03.RELEASE.DRUM.BLOCK (D.ADDR);
@BOX 12.1
-49 => PW0;
@BOX 13.1
-47 => PW0;
@BOX 14.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.OUT, 0, 0);
@BOX 15.1
END
@BOX 17.1
IF SIZE (D.NAME) => D.NAME.SIZE /= 0 AND
   [VALIDATE (BYTE (^D.NAME^ [0]), %C) /= 0 OR
     VALIDATE (BYTE (^D.NAME^ [D.NAME.SIZE - 1]), %C) /= 0]
@BOX 18.1
IF CHECK.NAME (D.NAME) /= 0
@BOX 19.1
-8 => PW0;
@BOX 20.1
-48 => PW0;
@BOX 22.1
IF D.NAME.SIZE =< 0
@BOX 23.1
-42 => PW0;
@BOX 24.1
-41 => PW0;
@END
@TITLE SYSCMD16.31(3,11)

@COL 9R
@COL 1S-13T-18T-3T-2R-4T-5T-6T-7R-8R-11R-12F
@COL 14R-19R-10R-16R-17N-15N

@ROW 2-10
@ROW 3-19
@ROW 5-16
@ROW 9-6
@ROW 11-17
@ROW 12-15
@ROW 18-14

@FLOW 1-13OK-18NO-3NO-2-4YES-5NO-6OK-7-11-12
@FLOW 13INVALID-14-15-12
@FLOW 18YES-19-15
@FLOW 3YES-10-17-11
@FLOW 4NO-16-17
@FLOW 5YES-9-11
@FLOW 6FAIL-8-11

@BOX 1.0
DELETE SUB DIR (DIRECTORY NAME)
@BOX 2.0
CHECK IN
[SYS01]
@BOX 3.0
DOES DIRECTORY NAME INCLUDE
ANY INVALID CHARACTERS?
@BOX 4.0
DIRECTORY CURRENTLY
EXISTS?
@BOX 5.0
DOES DIRECTORY HAVE ANY
SUBDIRECTORIES/FILES?
@BOX 6.0
DELETE USER MASTER BLOCK
ENTRY FOR THE DIRECTORY
AND SECURE IT
@BOX 7.0
RELEASE DISC SPACE PREVIOUSLY
OCCUPIED BY DIRECTORY
@BOX 8.0
RESET USER MASTER BLOCK
@BOX 9.0
RETURN FAULT STATUS -40
(DIRECTORY IS NOT EMPTY)
@BOX 10.0
RETURN FAULT STATUS -48
(INVALID CHARACTER IN
 FILE/DIRECTORY NAME)
@BOX 11.0
CHECK OUT
[SYS01]
@BOX 12.0
END
@BOX 13.0
VALIDATE DIRECTORY NAME
@BOX 14.0
RETURN FAULT STATUS -8
(VALIDATE FAIL)
@BOX 16.0
RETURN FAULT STATUS -43
(FILE/DIRECTORY NAME
 DOES NOT EXIST)
@BOX 18.0
IS DIRECTORY NAME
NOT SPECIFIED?
@BOX 19.0
RETURN FAULT STATUS -42
(INVALID DIRECTORY PATH/NAME)
@BOX 1.1
PROC DELETE.SUBDIR (D.NAME);
INTEGER FATHER, L.BROTHER, D.NAME.SIZE, REQ.DIR, OLD.SIZE;
0 => PW0;
@BOX 2.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.IN, 0, 0);
@BOX 3.1
IF CHECK.NAME (D.NAME) /= 0
@BOX 4.1
VALIDATE.PATH (D.NAME, 0, 1);
PW1 => REQ.DIR;
PW2 => FATHER;
PW3 => L.BROTHER;
IF PW0 /= 0
@BOX 5.1
SELECT USER.MB.TABLE [REQ.DIR] OF USER.MB^;
IF NEXT.LEVEL >= 0 OR
   NO.OF.FILES OF DIR.0^ > 0
@BOX 6.1
IF FATHER = L.BROTHER THEN
   SAME.LEVEL => NEXT.LEVEL OF USER.MB.TABLE [FATHER] OF USER.MB^;
ELSE
   SAME.LEVEL => SAME.LEVEL OF USER.MB.TABLE [L.BROTHER] OF USER.MB^;
FI
DIR.SIZE => OLD.SIZE;
0 => DIR.SIZE;
SECURE.USER.MB ();
IF PW0 /= 0
@BOX 7.1
SYS03.RELEASE.DRUM.BLOCK (DIR.DISC.ADDR);
@BOX 8.1
IF FATHER = L.BROTHER  THEN
   REQ.DIR => NEXT.LEVEL OF USER.MB.TABLE [FATHER] OF USER.MB^;
ELSE
   REQ.DIR => SAME.LEVEL OF USER.MB.TABLE [L.BROTHER] OF USER.MB^;
FI
OLD.SIZE => DIR.SIZE;
@BOX 9.1
-40 => PW0;
@BOX 10.1
-48 => PW0;
@BOX 11.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.OUT, 0, 0);
@BOX 12.1
END
@BOX 13.1
IF SIZE (D.NAME) => D.NAME.SIZE /= 0 AND
   [VALIDATE (BYTE (^D.NAME^ [0]), %C) /= 0 OR
    VALIDATE (BYTE (^D.NAME^ [D.NAME.SIZE - 1]), %C) /= 0]
@BOX 14.1
-8 => PW0;
@BOX 16.1
-43 => PW0;
@BOX 18.1
IF D.NAME.SIZE =< 0
@BOX 19.1
-42 => PW0;
@END
@TITLE SYSCMD16.32(3,11)

@COL 1S-2R-16T-3T-4R-5T-15R-6T-7T-8T-12R-11R-13R-14F
@COL 9T-10R

@ROW 15-9
@ROW 6-10

@FLOW 1-2-16OK-3OK-4-5OK-15-6YES-7NO-8NO MORE-12-11-13-14
@FLOW 16FAIL-11
@FLOW 5NO MORE-9YES-10-11
@FLOW 3FAIL-11
@FLOW 7YES-5
@FLOW 6NO-12
@FLOW 9NO-12
@FLOW 8EXIST-7

@BOX 1.0
VALIDATE PATH (DIRECTORY PATH, USER NAME, NEED DIRECTORY)
@BOX 2.0
CHECK IN
[SYS01]
@BOX 3.0
GET USER MASTER BLOCK
@BOX 4.0
FIND ROOT DIRECTORY RELATIVE
TO WHICH LOCAL DIRECTORY NAME
IS SPECIFIED,MAKE IT CURRENT
SEARCH DIRECTORY
@BOX 5.0
EXTRACT NEXT DIRECTORY NAME
FROM LOCAL DIRECTORY NAME
@BOX 6.0
DOES CURRENT SEARCH DIRECTORY
HAVE A SUBDIRECTORY?
@BOX 7.0
IS THIS THE SAME AS THE
EXTRACTED SUBDIRECTORY?
@BOX 8.0
GET NEXT SUBDIRECTORY OF
CURRENT SEARCH DIRECTORY
@BOX 9.0
IS LOCAL DIRECTORY NAME
SYNTACTICALLY CORRECT?
@BOX 10.0
RETRIEVE THE LAST SUBDIRECTORY
FROM DISC IF REQUESTED
@BOX 11.0
RETURN INDEX TO THE USER
MASTER BLOCK FOR THE LAST
SUBDIRECTORY, ITS FATHER &
IMMEDIATE LEFT BROTHER &
THE ROOT DIRECTORY
@BOX 12.0
RETURN FAULT STATUS -42
(INVALID DIRECTORY PATH/NAME)
@BOX 13.0
CHECK OUT
[SYS01]
@BOX 14.0
END
@BOX 15.0
SET NEW CURRENT
SEARCH DIRECTORY
@BOX 16.0
GET USER IDENTIFICATION
OF USER SPECIFIED
@BOX 1.1
PROC VALIDATE.PATH (DIR.PATH, U.NAME, NEED.DIR);
INTEGER I, INDEX, PATH.SIZE, START.PTR, SUBDIR.PTR,
        FATHER, L.BROTHER, ROOT, NEXT.DIR.ID, NEXT.UMB.ID;
ADDR [LOGICAL8] SUB.DIR;
PSPEC NEXT.DIR (ADDR [LOGICAL8]) / ADDR [LOGICAL8];
#SYSCMD16.32.1
-1 => INDEX => FATHER => L.BROTHER;
0 => START.PTR => PW0;
@BOX 2.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.IN, 0, 0);
@BOX 3.1
GET.USER.MB (NEXT.UMB.ID);
IF PW0 /=0
@BOX 4.1
IF U.NAME = 0 THEN
   DIR.ID OF C.FILE.VARS^ => INDEX;
ELSE
   0 => INDEX;
FI
IF DIR.PATH^ [0] = "/" THEN
   1 => START.PTR;
   0 => INDEX;
FI
INDEX => ROOT => FATHER;
@BOX 5.1
SELECT USER.MB^;
SIZE (DIR.PATH) - 1 => PATH.SIZE;
NEXT.DIR (PART (DIR.PATH, START.PTR, PATH.SIZE)) => SUB.DIR;
IF SUBDIR.PTR < 0
@BOX 6.1
IF NEXT.LEVEL OF USER.MB.TABLE [INDEX] => INDEX < 0
@BOX 7.1
IF COMPARE.NAME (SUBDIR, ^DIR.NAME OF USER.MB.TABLE [INDEX]) = 0
@BOX 8.1
INDEX => L.BROTHER;
IF SAME.LEVEL OF USER.MB.TABLE [INDEX] => INDEX >= 0
@BOX 9.1
IF PATH.SIZE /= -1 AND [START.PTR =< PATH.SIZE OR
   DIR.PATH^ [PATH.SIZE] = "/"]
@BOX 10.1
IF NEED.DIR = 1 THEN
   CURRENT.UMB.ID * NO.OF.DIRS +
       INDEX => NEXT.DIR.ID;
   GET.DIR(NEXT.DIR.ID);
FI
@BOX 11.1
INDEX => PW1;
FATHER => PW2;
L.BROTHER => PW3;
ROOT => PW4;
@BOX 12.1
-42 => PW0;
@BOX 13.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.OUT, 0, 0);
@BOX 14.1
END
@BOX 15.1
SUBDIR.PTR + 2 + START.PTR => START.PTR;
INDEX => FATHER => L.BROTHER;
@BOX 16.1
IF U.NAME = 0 THEN
   MAKE (FILE.VARS, 0, SYS13.GET.PRB (-1, 16)) => C.FILE.VARS;
   USER.ID OF C.FILE.VARS^ => NEXT.UMB.ID;
ELSE
   SYS17.FIND.UID (U.NAME);
   PW1 => NEXT.UMB.ID;
FI
IF PW0 /= 0
@END
@TITLE SYSCMD16.32.1(3,11)

@COL 1S-2T-3R-4R-5F

@FLOW 1-2YES-3-4-5
@FLOW 2NO-4
@BOX 1.0
NEXT DIR (DIR PATH)
@BOX 2.0
IS DIR PATH SPECIFIED?
@BOX 3.0
FIND NEXT
SUBDIRECTORY NAME
@BOX 4.0
RETURN  NEXT
SUBDIRECTORY NAME
@BOX 5.0
END
@BOX 1.1
PROC NEXT.DIR (DIR.PATH);
INTEGER I, MAXCH;
@BOX 2.1
0 => I;
IF SIZE (DIR.PATH) => MAXCH =< 0
@BOX 3.1
-1 => I;
WHILE 1 +> I < MAXCH AND DIR.PATH^ [I] /= "/" DO OD
@BOX 4.1
PART (DIR.PATH, 0, I - 1 => SUBDIR.PTR) => NEXT.DIR;
@BOX 5.1
END
@END
@TITLE SYSCMD16.33(3,11)

@COL 1S-2R-4T-5T-6R-11T-7R-9R-10F
@COL 8R

@ROW 7-8

@FLOW 1-2-4NO-5NO-6-11TRANSFER FAIL-7-9-10
@FLOW 5YES-9
@FLOW 4YES-8-9
@FLOW 11OK-8

@BOX 1.0
GET USER MB (NEXT USER MB ID)
@BOX 2.0
CHECK IN
[SYS01]
@BOX 4.0
USER MASTER BLOCK
CURRENTLY AVAILABLE?
@BOX 5.0
USER MASTER BLOCK
ALREADY IN (MAIN) STORE?
@BOX 6.0
FIND USER MASTER
BLOCK ADDRESS
@BOCX 7.0
RETURN FAULT STATUS -49
(DISC TRANSFER FAILED)
@BOX 8.0
SET POINTER TO USER
MASTER BLOCK
@BOX 9.0
CHECK OUT
[SYS01]
@BOX 10.0
END
@BOX 11.0
ENTER INTERRUPT LEVEL
TO RETRIEVE USER MASTER BLOCK
[SYSINT16.1]
@BOX 1.1
PROC GET.USER.MB (NEXT.UMB.ID);
INTEGER I, SMALLEST.COUNT, LEAST.USED;
LOGICAL8 FLAG;
0 => PW0;
@BOX 2.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.IN, 0, 0);
@BOX 4.1
IF NEXT.UMB.ID = CURRENT.UMB.ID
@BOX 5.1
MAX.UMB.COUNT => SMALLEST.COUNT;
0 => FLAG;
FOR I < MAPPED.UMB.TABLE.SIZE DO
   SELECT MAPPED.UMB.TABLE [I];
   IF MAPPED.UMB.ID = NEXT.UMB.ID THEN
      1 => FLAG;
      I => CURRENT.UMB.FRAME;
      MAX.UMB.COUNT - 1 => COUNT;
      NEXT.UMB.ID => CURRENT.UMB.ID;
      MAKE (USER.MB.TYPE, 0, I * USER.MB.SIZE +
       1 * SYS14.PAGE.SIZE + FILE.SEG.ADDR) => USER.MB;
   ELSE
      IF COUNT < SMALLEST.COUNT THEN
         COUNT => SMALLEST.COUNT;
         I => LEAST.USED;
      FI
      1 -> COUNT;
   FI
OD
IF FLAG = 1
@BOX 6.1
NEXT.UMB.ID => CURRENT.UMB.ID => MAPPED.UMB.ID OF
   MAPPED.UMB.TABLE [LEAST.USED];
(CURRENT.UMB.ID * 2 + LATEST.VERSION [CURRENT.UMB.ID] OF SYS.MB^) *
  USER.MB.SIZE + USER.MB.START.ADDR => CURRENT.UMB.ADDR
    => FILE.TRANSFER.ADDR;
MAX.UMB.COUNT - 1 => COUNT OF MAPPED.UMB.TABLE [LEAST.USED];
LEAST.USED => CURRENT.UMB.FRAME;
@BOX 7.1
-49 => PW0;
-1 => CURRENT.UMB.ID => MAPPED.UMB.ID OF
         MAPPED.UMB.TABLE [LEAST.USED];
-1 => COUNT OF MAPPED.UMB.TABLE [LEAST.USED];
@BOX 8.1
MAKE (USER.MB.TYPE, 0, CURRENT.UMB.FRAME *
   USER.MB.SIZE + 1 * SYS14.PAGE.SIZE +
  FILE.SEG.ADDR) => USER.MB;
@BOX 9.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.OUT, 0, 0);
@BOX 10.1
END
@BOX 11.1
SYS13.ENTER.INT.LEVEL (^FILE.TRANSFER, 0, 1);
IF FILE.TRANSFER.STATUS = 0
@END
@TITLE SYSCMD16.34(3,11)

@COL 1S-2R-3T-4T-7R-8F
@COL 9N-5R-6R

@ROW 3-9
@ROW 7-5
@ROW 8-6

@FLOW 1-2-3OK-4OK-7-8
@FLOW 4FAILED-5-6-7
@FLOW 3FAILED-9-6-7

@BOX 1.0
SECURE USER MASTER BLOCK
@BOX 2.0
CHEVK IN
[SYS01]
@BOX 3.0
ENTER INTERRUPT LEVEL TO
SECURE COPY OF ACTIVE
USER MASTER BLOCK
@BOX 4.0
UPDATE & SECURE COPY
OF THE SYSTEM MASTER BLOCK
@BOX 5.0
RESET SYSTEM
MASTER BLOCK
@BOX 6.0
RETURN FAULT STATUS -49
(DISC TRANSFER FAILED)
@BOX 7.0
CHECK OUT
[SYS01]
@BOX 8.0
END
@BOX 1.1
PROC SECURE.USER.MB;
0 => PW0;
@BOX 2.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.IN, 0, 0);
@BOX 3.1
IF LATEST.VERSION [CURRENT.UMB.ID] OF SYS.MB^ = 0 THEN
   USER.MB.SIZE +> CURRENT.UMB.ADDR
ELSE
   USER.MB.SIZE -> CURRENT.UMB.ADDR
FI
CURRENT.UMB.ADDR => FILE.TRANSFER.ADDR;
SYS13.ENTER.INT.LEVEL (^FILE.TRANSFER, 1, 1);
IF FILE.TRANSFER.STATUS /= 0
@BOX 4.1
1 -=> LATEST.VERSION [CURRENT.UMB.ID] OF SYS.MB^;
1 +> GEN.NO OF SYS.MB^;
1 -=> CURRENT.SYS.MB.ADDR => FILE.TRANSFER.ADDR;
SYS13.ENTER.INT.LEVEL (^FILE.TRANSFER, 1, 0);
IF FILE.TRANSFER.STATUS /= 0
@BOX 5.1
1 -=> LATEST.VERSION [CURRENT.UMB.ID] OF SYS.MB^;
1 -> GEN.NO OF SYS.MB^;
1 -=> CURRENT.SYS.MB.ADDR;
@BOX 6.1
1 -=> CURRENT.UMB.ADDR;
-49 => PW0;
@BOX 7.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.OUT, 0, 0);
@BOX 8.1
END
@END
@TITLE SYSCMD16.35(3,11)

@COL 1S-2T-3R-4R-5F

@FLOW 1-2YES-3-4-5
@FLOW 2NO-4

@BOX 1.0
COMPARE NAME (NAME1, NAME2)
@BOX 2.0
DOES INDIVIDUAL CHARACTERS
MATCH?
@BOX 3.0
CHECK NEXT CHARACTER OF
THE LONGER NAME AGAINST NULL
@BOX 4.0
RETURN RESULT
@BOX 5.0
END
@BOX 1.1
PROC COMPARE.NAME (NAME1, NAME2);
INTEGER MAXCH1, MAXCH2, PTR, RESULT;
0 => RESULT;
@BOX 2.1
SIZE (NAME1) => MAXCH1;
16 => MAXCH2;
0 => PTR;
WHILE PTR < MAXCH1 AND PTR < MAXCH2 DO
   IF NAME1^ [PTR] /= NAME2^ [PTR] THEN
      1 => RESULT;
      ->DIFF;
   FI
   1 +> PTR;
OD
DIFF:IF RESULT = 1
@BOX 3.1
IF PTR < MAXCH1 AND NAME1^ [PTR] /= 0 THEN
   1 => RESULT;
FI
IF PTR < MAXCH2 AND NAME2^ [PTR] /= 0 THEN
   1 => RESULT;
FI
@BOX 4.1
RESULT => COMPARE.NAME;
@BOX 5.1
END
@END
@TITLE SYSCMD16.36(3,11)

@COL 1S-2T-3T-7R-4R-8R-6F
@COL 5R

@ROW 3-5

@FLOW 1-2FOUND-3OK-7-4-8-6
@FLOW 2FAILED-5-6
@FLOW 3FAILED-6

@BOX 1.0
RELEASE DIR NAME (REMOTE NAME)
@BOX 2.0
SEARCH REMOTE DIR TABLE
FOR THE REMOTE NAME
@BOX 3.0
REQUEST APPROPRIATE FILE
MANAGER TO RELEASE ENTRY
FOR REMOTE NAME
@BOX 4.0
RELEASE THE ENTRY FOR
THE REMOTE NAME IN
REMOTE DIR TABLE
@BOX 5.0
RETURN FAULT STATUS -43
(FILE/DIRECTORY NAME DOES NOT EXIST)
@BOX 6.0
END
@BOX 7.0
CHECK IN
[SYS01]
@BOX 8.0
CHECK OUT
[SYS01]
@BOX 1.1
PROC RELEASE.DIR.NAME (REM.NAME);
INTEGER REMOTE.DIR.NO, LOCAL.DIR.NO;
0 => PW0;
@BOX 2.1
IF CHECK.REMOTE (REM.NAME) => REMOTE.DIR.NO < 0
@BOX 3.1
PW1 => LOCAL.DIR.NO;
REMOTE.FILE.REQUEST (REMOTE.DIR.NO, 2, NIL.ADDR, NIL.L64, NIL.INT);
IF PW0 /= 0
@BOX 4.1
MAKE (FILE.VARS, 0, SYS13.GET.PRB (-1, 16)) => C.FILE.VARS;
SELECT C.FILE.VARS^;
-1 => REMOTE.TABLE [LOCAL.DIR.NO];
REMOTE.FREE => REMOTE.LINK OF REMOTE.DIRS [REMOTE.DIR.NO];
REMOTE.DIR.NO => REMOTE.FREE;
@BOX 5.1
-43 => PW0;
@BOX 6.1
END
@BOX 7.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.IN, 0, 0);
@BOX 8.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.OUT, 0, 0);
@END
@TITLE SYSCMD16.38(3,11)

@COL 1S-2R-3R-4R-5F

@FLOW 1-2-3-4-5

@BOX 1.0
STORE NAME (NAME, BUFFER)
@BOX 2.0
GET SIZE OF NAME
AND BUFFER
@BOX 3.0
COPY NAME TO BUFFER
@BOX 4.0
INITIALISE UNUSED PART
OF BUFFER TO ZERO
@BOX 5.0
END
@BOX 1.1
PROC STORE.NAME (NAME, BUFFER);
INTEGER N.SIZE, B.SIZE, PTR;
@BOX 2.1
SIZE (NAME) => N.SIZE;
16 => B.SIZE;
@BOX 3.1
0 => PTR;
WHILE PTR < N.SIZE AND
      PTR < B.SIZE DO
   NAME^ [PTR] => BUFFER^ [PTR];
   1 +> PTR;
OD
@BOX 4.1
WHILE PTR < B.SIZE DO
   0 => BUFFER^ [PTR];
   1 +> PTR;
OD
@BOX 5.1
END
@END

@TITLE SYSCMD16.39(3,111)

@COL 8R
@COL 1S-7T-3T-4R-6F

@ROW 8-3

@FLOW 1-7SPECIFIED-3VALID-4-6
@FLOW 3INVALID-6
@FLOW 7YES-8-6

@BOX 1.0
CHANGE ROOT DIR (UNAME, PASSWD)
@BOX 3.0
UNAME AND PASSWD VALID?
@BOX 4.0
SET USER ID OF REQUESTING
PROCESS TO THAT
OF SPECIFIED USER
@BOX 6.0
END
@BOX 7.0
PASSWORD NOT SPECIFIED?
@BOX 8.0
RETURN FAULT STATUS -25
(INVALID PASSWORD)
@BOX 1.1
PROC CHANGE.ROOT.DIR (U.NAME, PASSWD);
INTEGER REQ.UID;
0 => PW0;
@BOX 3.1
FIND.U (U.NAME, PASSWD);
PW1 => REQ.UID;
IF PW0 /= 0
@BOX 4.1
MAKE (FILE.VARS, 0, SYS13.GET.PRB (-1, 16)) => C.FILE.VARS;
REQ.UID => USER.ID OF C.FILE.VARS^;
0 => DIR.ID OF C.FILE.VARS^;
@BOX 6.1
END
@BOX 7.1
IF PASSWD = 0
@BOX 8.1
-25 => PW0;
@END
@TITLE SYSCMD16.40(3,11)

@COL 1S-25T-23T-3T-4T-6T-21T-7T-8R-9T-5R-15N-10R-11N-12F
@COL 26R-24R-17R-16N-18N

@ROW 23-26
@ROW 7-17
@ROW 15-16
@ROW 11-18

@FLOW 1-25OK-23LOCAL-3-4NO-6NO-21OK-7OK-8-9OK-5-15-10-11-12
@FLOW 23REMOTE-24-18
@FLOW 3FAIL-15
@FLOW 4YES-15
@FLOW 6YES-17-16-15
@FLOW 21FAIL-15
@FLOW 25INVALID-26-18-11
@FLOW 7FAIL-15
@FLOW 9FAIL-15

@BOX 1.0
CHANGE FILE SIZE(FILEPATH, USERNAME, NEW SIZE)
@BOX 3.0
START FILE REQUEST
[SYSCMD16.10]
@BOX 4.0
IS FILE NON-EXISTENT?
[SYSCMD16.13]
@BOX 5.0
RELEASE SEGMENT
[SYS14]
@BOX 6.0
IS FILE ALREADY OPEN?
@BOX 7.0
CHANGE SIZE ON DRUM
[SYS03]
@BOX 8.0
NOTE NEW FILE DATA
@BOX 9.0
SECURE DIRECTORY
@BOX 10.0
END FILE REQUEST
[SYSCMD16.11]
@BOX 12.0
END
@BOX 17.0
RETURN FAULT STATUS -44
(EXCLUSIVE ACCESS FAULT)
@BOX 21.0
ALLOCATE SYSTEM SEGMENT
[SYS14]
@BOX 23.0
IS FILE REMOTE?
[SYSCMD16.24]
@BOX 24.0
CHANGE REMOTE FILE SIZE
@BOX 25.0
VALIDATE FILE PATH
@BOX 26.0
RETURN FAULT STATUS -8
(VALIDATE FAIL)
@BOX 1.1
PROC CHANGE.FILE.SIZE (FILE.PATH, U.NAME, NEW.SIZE);
INTEGER FILE.NO, SSN, REMOTE.DIR.NO, F.PATH.SIZE, TEMP;
ADDR [LOGICAL8] F.NAME;
LOGICAL64 [1] L64.PARAMS;
INTEGER [1] INT.PARAMS;
ADDRESS8 [1] STRING.PARAMS;
0 => PW0;
@BOX 3.1
START.FILE.REQUEST (FILE.PATH, U.NAME, %20) => F.NAME;
IF PW0 /= 0
@BOX 4.1
IF FIND.FILE.ENTRY (F.NAME) => FILE.NO < 0
@BOX 5.1
SYS14.PROTECT (SSN, 1);
SYS14.RELEASE.SYS.SEGMENT (SSN);
@BOX 6.1
PW1 => SSN;
IF SSN >= 0
@BOX 7.1
IF NEW.SIZE =< 0 OR NEW.SIZE > SYS14.X.SEG.SIZE THEN
   SYS14.X.SEG.SIZE => NEW.SIZE;
FI
SYS03.CHANGE.DRUM.SEGMENT.SIZE (SSN, NEW.SIZE);
IF PW0 /= 0
@BOX 8.1
SYS03.SECURE.DRUM.SEGMENT (SSN);
SYS03.READ.DRUM.SEGMENT.ADDR (SSN) => DISC.ADDR;
SYS14.X.SEG !> STATUS;
NEW.SIZE - F.SIZE => TEMP;
TEMP +> FILE.STORE.USED OF DIR.0^;
TEMP +> TOTAL.FILE.SPACE OF USER.MB^;
NEW.SIZE => F.SIZE => C.SIZE;
@BOX 9.1
SECURE.DIR ();
IF PW0 /= 0
@BOX 10.1
END.FILE.REQUEST ();
@BOX 12.1
END
@BOX 17.1
-44 => PW0;
@BOX 21.1
SELECT DIR^ [FILE.NO];
SYS14.ALLOCATE.SYS.SEG (DISC.ADDR,
   F.SIZE, C.SIZE, STATUS) => SSN;
IF PW0 /= 0
@BOX 23.1
IF CHECK.REMOTE (U.NAME) => REMOTE.DIR.NO >= 0
@BOX 24.1
FILE.PATH => ADDRESS OF STRING.PARAMS [0];
NEW.SIZE => INT.PARAMS [0];
REMOTE.FILE.REQUEST (REMOTE.DIR.NO, %90,
   ^STRING.PARAMS, NIL.L64, ^INT.PARAMS);
@BOX 25.1
IF SIZE (FILE.PATH) => F.PATH.SIZE /= 0 AND
   [VALIDATE (BYTE (^FILE.PATH^ [0]), %C) /= 0 OR
    VALIDATE (BYTE (^FILE.PATH^ [F.PATH.SIZE - 1]), %C) /= 0]
@BOX 26.1
-8 => PW0;
@END


@TITLE SYSTSK16.1(3,11)

@COL 1S-11R-17R-2R-3R-4T-5R-6R-7R-8T-9T-15R-16R-10F

@FLOW 1-11-17-2-3-4-5-6-7-8NO-9NO-5
@FLOW 4AT END-15-16-10
@FLOW 8YES-4
@FLOW 9YES-8

@BOX 1.0
FILE TASK
@BOX 2.0
SELECT CURRENT MASTER BLOCK
@BOX 3.0
RESERVE DISC SPACE
FOR MASTER BLOCKS
[SYS03]
@BOX 4.0
FOR ALL USERS
@BOX 5.0
GET SUBDIRECTORY
[SYSCMD16.20]
@BOX 6.0
RESERVE DISC SPACE
FOR SUBDIRECTORY
[SYS03]
@BOX 7.0
RESERVE DISC SPACE
FOR ALL FILES IN
THE SUBDIRECTORY
@BOX 8.0
NO MORE SUBDIRECTORY?
@BOX 9.0
IS SUBDIRECTORY
EMPTY?
@BOX 10.0
END
@BOX 11.0
CHECK IN
[SYS01]
@BOX 15.0
NOTE DISC INITIALISATION
COMPLETE
@BOX 16.0
CHECK OUT
[SYS01]
@BOX 17.0
INITIALISE FILE SYSTEM
DATA STRUCTURES
@BOX 1.1
PROC FILE.TASK;
INTEGER USER, FILE, FILE.IDENT, FILE.SIZES,
        DISC.NO, DIR.NO, GENERATION, I;
@BOX 2.1
MAP (FILE.SEG, FILE.MAPPED.SEG, 0);
PW6 * SYS14.SEG.SIZE => FILE.SEG.ADDR;
MAKE (SYS.MB.ENTRY, 0, FILE.SEG.ADDR) => SYS.MB;
GET.SYS.MB (0);
GEN.NO OF SYS.MB^ => GENERATION;
GET.SYS.MB (1);
IF GEN.NO OF SYS.MB^ < GENERATION THEN
   GET.SYS.MB (0);
FI
@BOX 3.1
-1 => USER => CURRENT.DIR.ID => CURRENT.UMB.ID;
@BOX 4.1
0 => DIR.NO;
IF 1 +> USER >= NO.OF.USERS
@BOX 5.1
GET.DIR (USER * NO.OF.DIRS + DIR.NO);
@BOX 6.1
SYS03.RESERVE.DRUM.BLOCK (CURRENT.DIR.ADDR);
@BOX 7.1
NO.OF.FILES OF DIR.0^ => FILE;
WHILE 1 -> FILE >= 0 DO
   SYS03.RESERVE.DRUM.SEGMENT (DISC.ADDR OF DIR^ [FILE],
      F.SIZE OF DIR^ [FILE]);
OD
@BOX 8.1
IF 1 + > DIR.NO >= NO.OF.DIRS
@BOX 9.1
IF DIR.SIZE OF USER.MB.TABLE [DIR.NO] OF
   USER.MB^ = 0
@BOX 10.1
END
@BOX 11.1
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.IN, 0, 0);
@BOX 15.1
SYS03.DRUM.INITIALISATION.COMPLETE ();
@BOX 16.1
MAP (0, FILE.MAPPED.SEG, 0);
SYS13.ENTER.INT.LEVEL (^SYS01.CHECK.OUT, 0, 0);
@BOX 17.1
NO.OF.SYS.REMOTE.DIRS - 1 => REMOTE.FREE;
-1 => REMOTE.LINK OF REMOTE.DIRS [REMOTE.FREE];
WHILE REMOTE.FREE /= 0 DO
   REMOTE.FREE => REMOTE.LINK OF REMOTE.DIRS [1 -> REMOTE.FREE];
OD
FOR I < MAPPED.UMB.TABLE.SIZE DO
   SELECT MAPPED.UMB.TABLE [I];
   -1 => MAPPED.UMB.ID;
   0 => COUNT;
OD
@END


@TITLE SYSTSK16.2(3,11)

@COL 1S-2R-3F

@FLOW 1-2-3

@BOX 1.0
INIT FILE TASK
@BOX 2.0
INITIALISE SYSTEM DISC
@BOX 3.0
END
@BOX 1.1
PROC INIT.FILE.TASK;
@BOX 2.1
INIT.FILE.DISC ();
@BOX 3.1
END
@END

@TITLE SYSTSK16.3(3,11)

@COL 1S-7R-2R-3R-4R-6F


@FLOW 1-7-2-3-4-6

@BOX 1.0
INIT FILE DISC
@BOX 2.0
INITIALISE SYSTEM MASTER BLOCK
AND INITIAL USER MASTER BLOCK
@BOX 3.0
INITIALISE ROOT DIRECTORY
OF EACH USER
@BOX 4.0
CREATE ROOT DIRECTORY
FOR ALL USERS
@BOX 5.0
SECURE DIRECTORY
[SYSCMD16.12]
@BOX 6.0
END
@BOX 7.0
NOTE DISC INITIALISATION
COMPLETE
@BOX 1.1
PROC INIT.FILE.DISC;
INTEGER I, J;
ADDR FILE.SEG.ADDR;
ADDR FILE.VARS C.FILE.VARS;
@BOX 2.1
MAP (FILE.SEG, FILE.MAPPED.SEG, 0);
PW6 * SYS14.SEG.SIZE => FILE.SEG.ADDR;
MAKE (SYS.MB.ENTRY, 0, FILE.SEG.ADDR) => SYS.MB;
MAKE (USER.MB.TYPE, 0, SYS14.PAGE.SIZE + FILE.SEG.ADDR) => USER.MB;
MAKE (DIR.ENTRY, 0, DIR.SEG.ADDR + FILE.SEG.ADDR) => DIR.0;
SELECT SYS.MB^;
FOR I < NO.OF.USERS DO
   0 => LATEST.VERSION [I];
OD
0 => GEN.NO;
SYS.MB.START.ADDR => CURRENT.SYS.MB.ADDR;
SELECT USER.MB^;
0 => TOTAL.NO.OF.FILES => TOTAL.FILE.SPACE;
FOR I < NO.OF.DIRS DO
   SELECT USER.MB.TABLE [I];
   FOR J < 16 DO
      0 => DIR.NAME [J];
   OD
   0 => DIR.DISC.ADDR => DIR.SIZE;
   -1 => SAME.LEVEL => NEXT.LEVEL;
OD
1 => DIR.SIZE OF USER.MB.TABLE [0];
@BOX 3.1
0 => NO.OF.FILES OF DIR.0^ => FILE.STORE.USED OF DIR.0^ =>
  NO.OF.USERS.PERMITTED OF DIR.0^ => NO.OF.FILES.PERMITTED OF DIR.0^;
-1 => CURRENT.DIR.ID;
@BOX 4.1
FOR I < NO.OF.USERS DO
   I => CURRENT.UMB.ID * NO.OF.DIRS => CURRENT.DIR.ID;
   0 => OLD.DIR.SIZE => OLD.DIR.ADDR;
   1 => CURRENT.DIR.SIZE;
   (I * 2) * USER.MB.SIZE + USER.MB.START.ADDR => CURRENT.UMB.ADDR;
   SECURE.DIR ();
OD
@BOX 6.1
MAP (0, FILE.MAPPED.SEG, 0);
END
@BOX 7.1
SYS03.DRUM.INITIALISATION.COMPLETE ();
@END



