?? RIGHT := 110 ??

MODULE rmm$enforce_tape_security;

?? NEWTITLE := 'NOS/VE Resource Management : Enforce DOD level C2 tape security' ??
?? NEWTITLE := 'Overall Design of Tape Security', EJECT ??
{
{ When a volume is mounted, NOS/VE attempts to read labels on the volume
{ regardless of the FILE_LABEL_TYPE access specified.  Based on the results of
{ the attempt to read labels, the volume is classified as defined in the TYPE
{ column below:
{
{ TABLE 1:                  TAPE VOLUME CLASSIFICATION TERMINOLOGY
{
{ TYPE        Definition
{ ---------------------------------------------------------------------------
{ LG            Labeled for group whose members are defined in NOS/VE Validation
{               File and whose name is defined in VOL1 Owner Identifier
{
{ LU            Labeled for user whose name is defined in VOL1 Owner Identifier
{
{ LV            Labeled, written by NOS/VE but neither LG nor LU; may be
{               Public or Password Protected
{
{ LX            Labeled, written by another system, i.e. "external" to NOS/VE
{
{ UL            Unlabeled
{
{ INDETERMINATE None of the above.
{ ---------------------------------------------------------------------------
?? EJECT ??
{
{ Once a volume is classified, access to the volume may be controlled by the
{ NOS/VE Validation File, depending upon the TYPE of volume found.  Access to
{ an LU volume is based on the login-user for a temporary tape file or the
{ master catalog name (owner) for a permanent tape file.  Access to an LV
{ volume is determined solely by File Accessibility, Owner Identification, and
{ Volume Accessibility which are considered passwords.
{
{ TABLE 2:         NOS/VE VALIDATION FILE and VOLUME CLASSIFICATION
{
{ TYPE        REQUIRED VALIDATION
{ ---------------------------------------------------------------------------
{
{ LG            REMOVABLE_MEDIA_ACCESS: ((name access_modes))
{
{ LU            N/A
{
{ LV            N/A
{
{ LX            REMOVABLE_MEDIA_ACCESS: ((LABELED_EXTERNAL_TAPES access_modes))
{
{ UL            REMOVABLE_MEDIA_ACCESS: ((UNLABELED_TAPES access_modes))
{
{ INDETERMINATE REMOVABLE_MEDIA_ADMINISTRATION capability
{ ---------------------------------------------------------------------------
{ NOTE: If the volume begins with labels but the VOL1 or HDR1 label is missing
{ or there are more than 128 labels in the volume header label group, access
{ to the volume is restricted to someone with REMOVABLE_MEDIA_ADMINISTRATION
{ capability.
?? EJECT ??
{
{ The prerequisites for a labeled volume to be classified as a particular TYPE
{ are discussed below.  A volume is classified as UL if it contains no labels
{ at loadpoint or begins with a tapemark.  A volume is classified as
{ INDETERMINATE if the first block cannot be read due to parity or hardware
{ error.
{
{ TABLE 3:                  TAPE VOLUME CLASSIFICATION
{
{             IMPLEMENTATION    VOLUME         OWNER          FILE
{ TYPE        IDENTIFIER        ACCESSIBILITY  IDENTIFIER     ACCESSIBILITY
{               (HDR1)            (VOL1)        (VOL1)         (HDR1)
{ ---------------------------------------------------------------------------
{
{ LG          NOS/VE V2.0       A              &group name    a character
{
{ LU          NOS/VE V2.0       A              user name      a character
{
{ LV          NOS/VE V2.0       not A          a characters   a character
{             NOS/VE V1.0       a character    a characters   a character
{
{ LX          not NOS/VE V      a character    a characters   a character
{ ---------------------------------------------------------------------------
?? EJECT ??
{
{ A labeled volume may be described as password protected because one or
{ more of the fields discussed below may be interpreted by NOS/VE as a
{ password.  The term PUBLIC is only applied to LV and LX volumes because
{ these types are the only ones in which the three security fields may all
{ be set to SPACE.  In the LX case, the volume is considered PUBLIC to all
{ who have the LABELED_EXTERNAL_TAPES validation.
{
{ TABLE 4:        TERMINOLOGY: PUBLIC and PASSWORD PROTECTED
{
{ ADJECTIVE:    APPLIES TO     VOLUME         OWNER          FILE
{                              ACCESSIBILITY  IDENTIFIER     ACCESSIBILITY
{ ---------------------------------------------------------------------------
{
{ Public        LV, LX          <--- all three set to space  --->
{
{ Password
{ Protected     LG, LU                                       nonspace
{
{ Password
{ Protected     LV, LX          <--- one or more is nonspace --->
{ ---------------------------------------------------------------------------
?? EJECT ??
{
{ When you use CREATE_BLANK_LABELED_VOLUME to initialize labels on a volume,
{ the LABELING_CONVENTION parameter determines the kinds of labels and the
{ contents of the labels written to the volume, as follows:
{
{
{ TABLE 5:                 NOS/VE CREATE_BLANK_LABELED_VOLUME Command
{
{ LABELING                      VOL1      HDR1      HDR2         OTHER
{ CONVENTION                    Label     Label     Label        CONSIDERATIONS
{ ---------------------------------------------------------------------------
{
{ ANSI                          written   absent    absent       (1)
{
{ LG                            written   written   written      (2,7)
{
{ LU                            written   written   written      (3,7)
{
{ CDC_VERSION_TWO               written   written   written      (4,7)
{
{ CDC_VERSION_ONE               written   written   written      (5)
{
{ list of string                                                 (6)
{ ---------------------------------------------------------------------------
{ NOTES:
{
{   1.  The following parameters are disallowed: file_accessibility,
{       implementation_identifier, and removable_media_group.
{
{   2.  NOS/VE sets the HDR2 Extension fields to SPACE, the
{       removable_media_group parameter is required, and the owner_identifier
{       parameter is disallowed.  Volume Accessiblity defaults to A and is
{       required to be A.  File Accessiblity defaults to SPACE but may be set
{       to any a-character.  Implementation Identifier defaults to 'NOS/VE
{       V2.0' and is required to be 'NOS/VE V2.0'.
{
{   3.  NOS/VE sets the HDR2 Extension fields to SPACE, the owner_identifier
{       parameter is required, and the removable_media_group parameter is
{       disallowed.  Volume Accessiblity defaults to A and is required to be
{       A.  File Accessiblity defaults to SPACE but may be set to any
{       a-character.  Implementation Identifier defaults to 'NOS/VE V2.0' and
{       is required to be 'NOS/VE V2.0'.
{
{   4.  NOS/VE sets the HDR2 Extension fields to SPACE.  File Accessibility,
{       Owner Identifier, and Volume Accessibility default to SPACE but may be
{       set to any a-character.  Implementation Identifier defaults to 'NOS/VE
{       V2.0' and is required to be 'NOS/VE V2.0'.  Assuming that OI and VA
{       are not specified, the first user to write on the volume will determine
{       the future security of the volume:
{
{       a.  By default, the volume is labeled with the user as the owner.
{
{       b.  By specifying the REMOVALBE_MEDIA_GROUP parameter of the
{           CHANGE_TAPE_LABEL_ATTRIBUTES command, the volume becomes labeled
{           for a group.
{
{       c.  By specifying a value other than A for Volume Accessibility, the
{           values specified by the owner_identifier and volume_accessibility
{           become passwords.
{
{   5.  NOS/VE sets the HDR2 Extension fields to SPACE.  File Accessibility,
{       Owner Identifier, and Volume Accessibility default to SPACE but may be
{       set to any a-character.  Implementation Identifier defaults to 'NOS/VE
{       V1.0' and is required to be 'NOS/VE V1.0'.  Assuming that FA, OI, and
{       VA are not specified, the first user to write on the volume may
{       enhance the security of the volume through password protection.  The
{       user may specify a value for any of the following that you set to
{       SPACE:  File Accessibility, Owner Identifier and Volume Accessibility.
{       Subsequent accessors are required to provide these values which act as
{       passwords to the volume.
{
{   6.  The caller of CREATE_BLANK_LABELED_VOLUME may dictate which labels are
{       written by providing a list of string.  Each string is considered a
{       label.  The caller may prepare a label group that looks identical to
{       one of the preceding label groups or is quite different.  Parameters
{       specified to the command are substituted into the list of string.  A
{       VOL1 label is required.  If the file_accessibility or
{       implementation_identifier parameters are specified, a HDR1 label is
{       required.
{
{   7.  If you do not specify a value for File Accessibility.  The user may
{       enhance the security of the volume by defining a password for File
{       Accessibility using the CHANGE_TAPE_LABEL_ATTRIBUTES command prior to
{       writing on the volume.
?? EJECT ??
{
{ When a volume is mounted, NOS/VE categorizes the volume as blank or
{ nonblank.  The prerequisites for classifying a volume as blank are discussed
{ below.  Any TYPE of volume could be a blank volume.
{
{
{ TABLE 6:                 BLANK VOLUME CLASSIFICATION
{
{
{ TYPE        VOL1      HDR1      HDR2         EXPIRED           OTHER
{             Label     Label     Label                        CONSIDERATIONS
{ ---------------------------------------------------------------------------
{
{ LG,LU       present   present   present      Yes            VE Extension Fields
{                                                             in HDR2 are SPACE
{                                                             (1)
{
{ LG,LU       present   present   absent       Yes            (1)
{
{ LV          present   present   present      Yes            VE Extension Fields
{                                                             in HDR2 are SPACE
{                                                             (1, 2)
{
{ LV          present   present   absent       Yes            (1, 2)
{
{ LX          present   absent    absent       assumed        (1)
{
{ LX          present   present   absent       Yes            (1, 3)
{
{ LX          present   present   present      Yes            HDR2 Record Format
{                                                             Field is SPACE
{                                                             (1, 3)
{
{ UL          absent    absent    absent       N/A            First block is a
{                                                             Tapemark
{
{ NOTES:
{
{   1.  A labeled volume must have no data following the volume header label
{       group.
{
{   2.  The Implementation Identifier is 'NOS/VE V2.0'.  NOS/VE does not recognize
{       as blank labeled any volume whose II field is 'NOS/VE V1.0'.  This is done
{       to ensure access to any volume written by previous NOS/VE releases that
{       may have a blank label group as the first file on a multi-file set.  It was
{       possible to create such a volume in releases prior to R1.6.1 L780.
{
{   3.  The following fields must also be SPACE:  File Accessibility,
{       Implementation Identifier, Owner Identifier, and Volume Accessibility
{       ---------------------------------------------------------------------------
?? EJECT ??
{
{ If you have a labeled, blank volume, the following table discusses the
{ security options that you have when you first write on it.  When you write
{ on a labeled, blank volume, you do not need to specify REWRITE_LABELS=TRUE.
{ Depending upon the TYPE of the labeled, blank volume, you may only have one
{ opportunity to select the TYPE of security that you want enforced for your
{ nonblank volume.  Therefore, you should select from the options below and
{ make your CHANGE_TAPE_LABEL_ATTRIBUTES specification before writing on the
{ volume for the first time.
{
{
{ TABLE 7:            REWRITING LABELS ON A BLANK, LABELED VOLUME
{
{
{ FROM TYPE:               TO TYPE:                     CHATLA SPECIFICATION
{ ---------------------------------------------------------------------------
{
{ LG                       LG                           no specification required
{
{ LG                       LG, Password Protected       FA= a-character
{
{ LG, Password Protected   LG, Password Protected       Must match FA of HDR1
{
{ LU                       LU                           no specification required
{
{ LU                       LU, Password Protected       FA= a-character
{
{ LU, Password Protected   LU, Password Protected       Must match FA of HDR1
{
{ LV, (1)                  LG                           RMG=group name
{
{ LV, (1)                  LG, Password Protected       RMG=group name,
{                                                       FA= a-character
{
{ LV, (1,2)                LU                           no specification required
{
{ LV, (1)                  LU, Password Protected       FA= a-character
{
{ LV, (1,3)                LU, Password Protected       Must match existing FA
{
{ LV, PUBLIC (1)           LV, PUBLIC                   Must specify VA=NONE
{
{ LV, Password Protected   LV, Password Protected       Must match any existing
{     (1)                                               security field that is
{                                                       <> SPACE.  Any existing
{                                                       security field that is
{                                                       a SPACE may be set to
{                                                       an a-character.
{
{ LX                       LG                           RMG=group name
{
{ LX                       LG, Password Protected       RMG=group name
{                                                       FA= a character
{
{ LX                       LU                           no specification required
{
{ LX                       LU, Password Protected       FA= a character
{
{ LX                       LV, PUBLIC (1)               VA=NONE
{
{ LX                       LV, Password Protected (1)   Specify a character for
{                                                       FA, OI, and/or VA
{ ---------------------------------------------------------------------------
{
{ NOTES:
{
{   1.  The Implementation Identifier is 'NOS/VE V2.0'
{
{   2.  Existing VA must be SPACE or A
{
{   3.  Password Protected, FA is <> SPACE
{
?? EJECT ??

{ The transitions defined by TABLE 7 are also allowed when the volume is
{ nonblank with the exception of the following:
{
{    a. NOS/VE only rewrites labels on blank LX volumes.
{    b. Because LV volumes whose II field is 'NOS/VE V1.0' are never classified
{       as blank, the following transitions also exist for a non-blank volume:
{
{ FROM TYPE:               TO TYPE:                     CHATLA SPECIFICATION
{ ---------------------------------------------------------------------------
{ LV, PUBLIC               LV, PUBLIC                   no specification required
{
{ LV, PUBLIC               LV, Password Protected       Specify a character for
{                                                       FA, OI, and/or VA
{
{ LV, Password Protected   LV, Password Protected       Must match any existing
{                                                       security field that is
{                                                       <> SPACE.  Any existing
{                                                       security field that is
{                                                       a SPACE may be set to
{                                                       an a-character.
{
{ ---------------------------------------------------------------------------
?? OLDTITLE ??
?? NEWTITLE := 'Copy of SRB Documenation of Tape Security Feature', EJECT ??
{
{                   SRB Article for Basic Tape Security Feature
{                   -------------------------------------------
{ This feature has as its primary objectives the implementation of:
{
{   o DOD C2 level security for magnetic tapes
{
{   o Enforcement of expiration date for labeled tapes
{
{ By default, C2 tape security is not enabled.  You must use the
{ CHANGE_TAPE_VALIDATION command to set ENFORCE_TAPE_SECURITY to ON.  For the
{ following reasons, it is recommended that you plan to leave
{ ENFORCE_TAPE_SECURITY in the OFF condition until your upgrade to R1.6.1 is
{ complete and you are sure that you will not go back to the system you
{ installed prior to R1.6.1:
{
{   1.  This feature required an extensive set of changes to labeled tape
{       processing.  While every effort has been made to deliver a quality
{       system, your site may use tape in a manner that we have not
{       anticipated.  It will be easier to understand a potential problem with
{       security disabled.
{
{   2.  If you go back and forth between R1.6.1 and a previous release, you
{       may cause problems for tape users.  To cause problems you would have
{       to do all of the following:
{
{       a.  Create a tape that is labeled for a user or labeled for a group on
{           an R1.6.1 system,
{
{       b.  Rewrite the tape, specifying REWRITE_LABELS=TRUE, using your
{           previous level of NOS/VE
{
{       c.  Access the tape again using R1.6.1.
{
{       Step (b) causes the security classification of the tape to change from
{       labeled for a user or a group to password protected.  Previous
{       releases of NOS/VE will retain the File Accessibility (FA), Owner
{       Identifier (OI), and Volume Accessibility (VA) fields but will change
{       the Implementation Identifier from 'NOS/VE 2.0' to 'NOS/VE 1.0'.
{       Therefore, your users will have to specifiy VA=A and OI.  The OI will
{       either be the user name or the name of the Removable Media Access
{       Group, the latter preceded by '&'.  Note, all other kinds of tapes may
{       be interchanged between R1.6.1 and previous releases without impact.
{
{   3.  Before turning on ENFORCE_TAPE_SECURITY, you should also study whether
{       or not you want to enable labeling for an individual user or a group
{       of users.  There are some advantages (e.g.  enhanced security) and
{       disadvantages (e.g.  difficulty interchanging tapes among NOS/VE
{       users).  The ability to label a tape for a user or a group is
{       controlled by the CREATE_BLANK_LABELED_VOLUME command.  This command's
{       LABELING_CONVENTION parameter has a default variable that allows you
{       to easily establish your site's default policy.
{
{       If you set the labeling convention to CDC_VERSION_TWO or ANSI, you
{       enable enhanced security.  The first time the volume is written, the
{       user may choose to label it with the user as the owner or label it for
{       a group.  The user also may choose to leave the volume public or use
{       password protection.
{
{       You may also blank label a volume directly for a user or a group by
{       specifying the labeling conventions LABEL_FOR_USER or LABEL_FOR_GROUP.
{       The first user to write on the volume is constrained to be the owner
{       (LABEL_FOR_USER) or a member of the group (LABEL_FOR_GROUP) who has
{       been authorized for write access.
{
{
{       WARNING
{       ----------------------------------------------------------------------
{
{       If you label volumes for CDC_VERSION_TWO, you may encounter problems
{       reading the volume on a NOS/VE release other than R1.6.1.  This is
{       only a concern if the record type of the tape file is UNDEFINED (U).
{       Your users may be able to work around the problem by using the
{       SET_FILE_ATTRIBUTES, command before accessing the tape file, to
{       specify RECORD_TYPE=UNDEFINED and the BLOCK_TYPE that was specified
{       when the file was written.
{
{       The NOS/VE deadstart tape is an example of a magnetic tape that cannot
{       be read using the MAINTAIN_DEADSTART_SOFTWARE utility on a release
{       other than R1.6.1 because of this compatibility problem.
{
{       ----------------------------------------------------------------------
{
{       If you specify CDC_VERSION_ONE, the user is restricted to using
{       passwords for security.  If you plan to interchange a volume with a
{       previous NOS/VE release, this is the recommended labeling convention.
{       If you plan to interchange a volume with another vendor, use this
{       labeling convention (specify no values for the FILE_ACCESSIBILITY,
{       OWNER_IDENTIFIER, and VOLUME_ACCESSIBILTY parameters of the
{       CREATE_BLANK_LABELED_VOLUME command).
{
{       The CREATE_BLANK_LABELED_VOLUME command provides a default variable
{       for the LABELING_CONVENTION parameter so that you may establish a
{       default policy for your operators.
{
{ Set ENFORCE_TAPE_SECURITY to ON only after you are certain to remain on
{ NOS/VE R1.6.1 and you have read the Security manual.
{
{ To prepare for the introduction of tape security, we suggest that you do the
{ following:
{
{   1.  Prepare your validation file in advance:
{
{     - If you plan to allow labeling volumes for a user, you must ensure
{       that the user names in your validation files are less than or equal to
{       14 characters in length or are unique within the first 14 characters.
{       Otherwise, the identity of the owner of a volume may be ambiguous and
{       security may be compromised.
{
{     - If a user requires access to unlabeled tapes, validate the user for
{       UNLABELEED_TAPES using the REMOVABLE_MEDIA_ACCESS field.  You may
{       allow access of READ, WRITE, or (READ, WRITE).
{
{           /sou
{           sou/admv
{           ADMV/change_user BTS
{           Changing user BTS.
{           CHAU/charma add=((unlabeled_tapes (read)))
{
{     - If a user requires access to labeled tapes written by another vendor
{       or a Control Data system other than NOS/VE, validate the user for
{       LABELED_EXTERNAL_TAPES using the REMOVABLE_MEDIA_ACCESS field.  You
{       may allow access of READ, WRITE, or (READ, WRITE).
{
{     - NOS/VE's release materials are now labeled for the group
{       RELEASE_TAPES.  Anyone using the tapes in conjuction with deadstart
{       does not require validation.  However, if you have users who access
{       release materials in other contexts (e.g.
{       MAINTAIN_DEADSTART_SOFTWARE, you must validate them for RELEASE_TAPES
{       using the REMOVABLE_MEDIA_ACCESS field.  This is true regardless of
{       whether or not tape security is enabled.
{
{     - Anyone who needs access to Express Deadstart Dump tapes or other
{       CYBER memory dumps must be validated for the group DUMP_TAPES for READ
{       access.  You must prelabel tapes that are used for dumping memory.
{       EDD will retain the VOL1 and HDR1 labels during the dump but will not
{       label an unlabeled tape for this group.  Labeling the volume for the
{       group DUMP_TAPES ensures that Control Data will be able to read a dump
{       tape that you send in for analysis.
{
{     - If you have groups of users who share access to a set of tapes, you
{       may wish to assign these users to a REMOVABLE_MEDIA_ACCESS group.
{       Unlike DUMP_TAPES, LABELED_EXTERNAL_TAPES, RELEASE_TAPES, and
{       UNLABELED_TAPES, which are reserved names, you may create any other 13
{       character name in the REMOVABLE_MEDIA_ACCESS field and control access
{       to other types of tapes.  Members of this group may label their tapes
{       for this group and share access to the tapes.
{
{   2.  By default, if you initialize a volume using R1.6.1 and use it for a
{       file or catalog backup, the volume becomes labeled for the user
{       $SYSTEM.  If you have allowed users to request these tapes and restore
{       their own files in the past, you will have to change the process.
{       Here are two suggestions:
{
{       a.  One solution would be to catalog your backup file's volume set as
{           a labeled, permanent tape file and permit those who need to use
{           it.
{
{       b.  Another solution is to define a group using the
{           REMOVABLE_MEDIA_ACCESS field and validate the users who need READ
{           access to the backup file's volume set.  Then, when you introduce
{           R1.6.1 to production, you can use the new
{           CREATE_BLANK_LABELED_VOLUME command to blank label your backup
{           volumes for this group.
{
{ If tape security is not an issue at your site, you may leave
{ ENFORCE_TAPE_SECURITY in the OFF condition.  You should find that accessing
{ labeled tapes is compatible with previous releases with the exception that
{ the expiration date is now enforced.  Expiration date enforcement is
{ independent of the ENFORCE_TAPE_SECURITY selection.
{
{ If you intend to leave ENFORCE_TAPE_SECURITY in the OFF condition and you
{ are satisfied with the tape security already in effect at your site, you may
{ want to:
{
{   1.  Set the default variable for the LABELING_CONVENTION parameter of
{       CREATE_BLANK_LABELED_VOLUME to CDC_VERSION_ONE.  This ensures that the
{       contents of labels are consistent with previous releases.  If the
{       LABELING_CONVENTION is set to another value (it defaults to
{       CDC_VERSION_TWO), the user's name is stored in the Owner Identifier
{       field and the Volume Accessibility field is set to A when the user
{       rewrites a blank labeled volume, regardless of the
{       ENFORCE_TAPE_SECURITY selection.
{
{   2.  Remove the DISPLAY_VOLUME_CLASSIFICATION command from the
{       $SYSTEM.OSF$SITE_COMMAND_LIBRARY.  This command displays the contents
{       of the security fields for an ordinary user when tape security is off.
{       When tape security is on, it does not reveal any secure information.
{       The command consists of a program description and an object module
{       called RAM$DISPLAY_VOL_CLASSIFICATION.
{
{ In addition to the features identified above, the following changes and
{ enhancments are implemented.  The follwing is independent of the
{ ENFORCE_TAPE_SECURITY selection:
{
{   1.  The expiration date is now enforced when rewriting an ANSI file.
{
{   2.  The CHANGE_BACKUP_LABEL_TYPE and DISPLAY_BACKUP_LABEL_TYPE commands
{       are no longer supported.  A WARNING message is emitted when either
{       command is referenced.  These commands have been unnecessary since
{       R1.5.1 when the FILE_LABEL_TYPE default was changed to LABELED.  These
{       commands will be deleted in the next release.
{
{   3.  Repair Solution 3 (a and b) have been enhanced.  An optional VSN_LIST
{       parameter now allows input of a list of recorded VSNS that do not
{       conform to the rigid constraints imposed by the VSN_PREFIX, VSN_COUNT,
{       INCREMENT_SCHEME, etc.  parameters.  Specification of the VSN_LIST
{       parameter inactivates any specification of VSN_PREFIX et.al.  The
{       VSN_PREFIX parameter is made optional.  Refer to the System
{       Performance and Maintenance manual for a description of Repair
{       Solution 3.
{
{   4.  All of the permanenent file maintenance procedures (i.e.
{       CREATE_FULL_BACKUP, CREATE_PARTIAL_BACKUP, RESTORE_CATALOGED_FILES,
{       RESTORE_UNRECONCILED_FILES, RESTORE_UNRECONCILED_CATALOGS,
{       CREATE_AGED_FILE_BACKUP, and CREATE_CATALOG_BACKUP) have been improved
{       to support a VSN_LIST parameter.  See the discussion in (3) above.
{
{       CREATE_FULL_BACKUP and CREATE_PARTIAL_BACKUP no longer depend upon the
{       presence of ADMINISTER_VALIDATIONS to obtain the list of families.
{
{       References to CHANGE_BACKUP_LABEL_TYPE are removed from the procs.
{
{       The procs are modified to take advantage of SCL new types.
{
{   5.  The ability to mount an UNLABELED tape and access it with a
{       FILE_LABEL_TYPE of LABELED is removed from the system.  This was
{       originally done to migrate users from unlabeled to labeled backups.
{
{   6.  You may now make one or more copies of a file backup by using
{       CREATE_FILE_CONNECTION, for example:
{
{        reserve_resource mt9$6250=2
{        reqmt $local.copya rvsnl=(a1 a2 a3 a4 ...) t=mt9$6250 r=true
{        reqmt $local.copyb rvsnl=(b1 b2 b3 b4 ...) t=mt9$6250 r=true
{        change_tape_label_attributes $local.copya file_set_position=bos ..
{              rewrite_labels=true
{        change_tape_label_attributes $local.copyb file_set_position=bos ..
{              rewrite_labels=true
{        create_file_connection $local.x $local.copya
{        create_file_connection $local.x $local.copyb
{        bacpf backup_file=$local.x list=$local.copya_list
{        backup_all_files
{        quit
{        delete_file_connection $local.x $local.copya
{        delete_file_connection $local.x $local.copyb
{        detach_file ($local.copya $local.copyb)
{        release_resource mt9$6250=2
{
{     Restrictions:
{
{       a) Only one listing is produced.  The oldest connection's tape vsns
{           are given in the listing.  In the above example, COPYA is the
{           oldest because its connection was established before COPYB's
{           connection.
{       b) Both tape files must have the same FILE_LABEL_TYPE (labeled or
{           unlabeled)
{       c) Normally, BACPF specifies FILE_SET_POSITION=BEGINNING_OF_SET and
{           REWRITE_LABELS=TRUE on your behalf when opening the BACKUP_FILE.
{           However, when the BACKUP_FILE is the subject of a file connection,
{           the user is required to specify these two parameters for each copy
{           desired.
{       d) All TARGET files of the connection must be the same device class
{       e) The volume sets will be logical but not physical duplicates.
{           Actual location of files may differ from one volume set to another
{           due to variation in the capacity of volumes in each volume set.
{
{     Behavior:
{       a) Works well with dual tape channels
{       b) When one copy needs a tape mounted or operator intervention, both
{          copies stop.
{       c) Works equally well for backup to mass storage or to tape
{
{
{   7.  You may now read and write multiple files with differing record and
{       block types on an unlabeled volume without having to detach and
{       request the tape for each file.  The SET_FILE_ATTRIBUTES and
{       CHANGE_TAPE_LABEL_ATTRIBUTES commands as well as FSP$OPEN_FILE now
{       allow Record Type and Block Type (and 5 other attributes listed below)
{       to be changed for each file on the volume set.  For labeled tapes, the
{       use of SETFA is now equivalent to CHATLA for Block Type, Character
{       Conversion, Character Set, Maximum Block Length, Maximum Record
{       Length, Padding Character, and Record Type.
{
{   8.  The INITIALIZE_TAPE_VOLUME and LABEL_TAPE_VOLUMES commands are retired
{       (but still supported).  The new command CREATE_BLANK_LABELED_VOLUME
{       combines the features of the old commands and adds several new ones:
{
{       a.  An UNLOAD_VOLUME parameter is provided to allow the operator to
{           leave the tape mounted after initialization for immediate
{           assignment to a requesting job.
{
{       b.  You may now control the presentation of the confirmation menu for
{           each volume initialized.
{
{       c.  You may now provide a list of tape unit names; NOS/VE uses the
{           units in a round-robin fashion.
{
{       d.  You may now provide your own list of RECORDED_VSNS and
{           EXTERNAL_VSNS instead of the awkward and restrictive parameters of
{           LABEL_TAPE_VOLUMES.  The $VSN_LIST function may be used
{           effectively to create the list.
{
{       e.  When processing a list of volumes, you may now provide an integer
{           VAR parameter to obtain the number of volumes that were
{           successfully initialized before a failure is reported.
{
{       f.  Several parameters are added to allow the operator to create a
{           secure, blank labeled tape.
{
{   9.  An UNLOAD_VOLUME parameter is added to the DETACH_FILE command to
{       allow the user to leave the tape mounted for immediate reassignment to
{       the same job or another job.
{
{  10.  A CREATE_BLANK_UNLABELED_VOLUME command is provided to allow an
{       operator to create an unlabeled volume.  Three tapemarks are written
{       on the volume.  Many of the features of this command are in common
{       with those discussed for CREATE_BLANK_LABELED_VOLUME, above.
{
{  11.  Header Labels and Trailer Labels are now provided by the
{       $TAPE_LABEL_ATTRIBUTES function and the DISPLAY_TAPE_LABEL_ATTRIBUTES
{       command.  Security fields are now ADVANCED and only visible to a
{       Removable Media Administrator.
{
{  12.  NOS/VE now detects that a blank labeled volume has been mounted.  If
{       you try to read from the volume or write at $EOI you now get an
{       abnormal status.  You no longer need to specify REWRITE_LABELS=TRUE to
{       rewrite labels on a blank volume.  This enhancement pertains to any
{       volume labeled on this new release.
{
{       This enhancement does not pertain to blank volumes that were blank
{       labeled on previous NOS/VE releases.  This is because in the past, you
{       could append a new ANSI file beyond the empty file that is written in
{       a NOS/VE blank label group.  This is no longer allowed in the new
{       release.  However, to allow you to read volumes that retained the
{       empty file at the beginning, we do not classify such volumes as blank.
{
{  13.  A message is recorded in the job log for each ANSI file read or
{       written.  The message displays the File Section Number, File Sequence
{       Number, and Block Count.
{
{  14.  A user may opt to display to the job log all of the labels accessed
{       in the file set.  Secure fields are only made visible to an Removable
{       Media Administrator.  Put the following in the user or system prolog:
{
{       var
{         rmv$log_ansi_labels: (job) boolean = true
{       varend
{
{  15.  The Block Count in an EOF1 or EOV1 label is compared to the actual
{       block count calculated as NOS/VE reads the ANSI file.  If the values
{       differ, a warning message is written to $ERRORS and to the job log.
{
{  16.  NOS/VE now reads labeled tapes that have tapemarks embedded in the
{       data field of an ANSI file.  This will make it easier to write CYBIL
{       programs that read NOS and NOS/BE labeled tapes on NOS/VE.  Each
{       tapemark returns the FILE_POSITION of AMC$EOI and normal status when
{       using GET at the program interface level of NOS/VE.  Reading the file
{       completely is only possible from the program interface because the
{       $ASIS open position is not supported for labeled tapes.
{
{  17.  Some labeled tapes have non-numeric values in fields defined to be
{       numeric (including Creation Date and Expiration Date) by the ANSI
{       Standard.  In the past, these invalid fields may have prevented the
{       volume from being processed by NOS/VE.  In NOS/VE R1.6.1, invalid
{       numeric fields are displayed in the job log and are set to either
{       SPACE or a legal numeric value.
{
{  18.  Some labeled tapes do not conform to ANSI conventions concerning the
{       numbering of ANSI files.  In the past, if file sequencing was not
{       proper, the volume could not be processed on NOS/VE.  In R1.6.1,
{       NOS/VE does not depend upon the file sequencing to be correct.
{       Numbering is based on the actual displacement of the file from the
{       beginning of volume set rather than the value in the HDR1 label.
{
{  19.  A message is now recorded in the job log when the initial volume of
{       the volume set is not the first volume of the file set.  The initial
{       volume of the file set is one whose File Section and File Sequence
{       Numbers are both one (1).  Access to the volume is allowed, however.
{
{  20.  In the past, abnormal status was returned when a user tried to write
{       with a file reference of $EOI when the file was positioned at end of
{       set.  Now, a new ANSI file may be written if the FILE_SET_POSITION is
{       END_OF_SET, NEXT_FILE, or FILE_SEQUENCE_POSITION and the file set is
{       currently positioned at end of set.
{
{  21.  The VEDISPLAY, TAPE_MOUNT has been changed.  A mount request for a
{       volume now may consist of up to three lines.  Previously, up to two
{       lines were displayed.
{
{       Changes to the first line of the display include:
{
{       - Instead of RING (IN, OUT), we now have M (for mode) and values of W
{         (write) and R (read).
{
{       - Instead of LAB (YES, NO), we now have A (for Access) and values of L
{         (labeled), U (unlabeled), and N (non-standard_labeled).
{
{       - The previous VSN is now visible in addition to the next VSN
{
{       The second line is new.  It contains the identity of the requesting
{       user in the form of Family, User, Account and Project.  The inclusion
{       of the second line as a whole or in part is controlled by a new site
{       hook, RMM$ENFORCE_TAPE_SECURITY.
{
{       The third line is now reserved for the Removable Media Management
{       Group and Location.  The Removable Media Location is now recovered via
{       active job recovery and reappears in the TAPE_MOUNT display after job
{       recovery.
{
{  22.  The enforcement of expiration date and tape security is totally under
{       the control of the new site hook, RMM$ENFORCE_TAPE_SECURITY.  The site
{       may review or change the default policies at their discretion.  If the
{       site changes the module, it is responsible for any consequences that
{       may arise.
{
{  23.  To aid in the transition to a secure tape environment, the
{       DISPLAY_VOLUME_CLASSIFICATION command is provided on
{       $SYSTEM.OSF$SITE_COMMAND_LIBRARY.
{
{       a.  When tape security is off, the command allows the owner of a tape
{           volume to determine how NOS/VE will classsify the volume when
{           security is enabled.  This is the only command that reveals the
{           security fields File Accessibility, Owner Identifier, and Volume
{           Accessibility to an ordinary user.  Therefore, you may want to
{           remove this command from the library, if you do not want this
{           information revealed and you do not intend to enable tape
{           security.  Refer to the earlier note.
{
{       b.  When tape security is enabled, the command only reveals secure
{           information to a user executing within the SYSTEM_OPERATOR_UTILITY
{           with the REMOVABLE_MEDIA_ADMINISTRATION capability active.
{
{  24.  For a volume written by EP/IX and read on NOS/VE, the EP/IX security
{       policies are enforced.  Therefore, if your EP/IX users create private
{       volumes (those whose VA='0' and whose OI=<EP/IX user name>, these
{       users must have the same user name in their NOS/VE validation file to
{       access their private volumes.
{
{       EP/IX tapes are considered "external" to NOS/VE.  Therefore, any user
{       who must read an EP/IX tape on NOS/VE must be validated for the
{       LABELED_EXTERNAL_TAPES REMOVABLE_MEDIA_ACCESS field.
{
{       Ordinarily, if the File Accessibility, Owner Identifier, or Volume
{       Accessibility field of an "external" volume is nonblank, the field is
{       considered to be a password that the accessor is required to match in
{       order to gain access to the volume.  Because these fields are not
{       passwords on an EP/IX volume, this requirement is waived on NOS/VE.
{       The security fields are given the same meaning in NOS/VE as they are
{       in EP/IX.
{
{                    Functional Differences
{                    ----------------------
{
{ The Basic Tape Security (BTS) feature introduces the following functional
{ differences that may affect existing procedures and programs EVEN THOUGH
{ SECURITY IS DISABLED:
{
{   1.  The expiration date is now enforced.  You may only rewrite an expired
{       tape.  If you did not specify an expiration date on the
{       CHANGE_TAPE_LABEL_ATTRIBUTES command when you last wrote the tape, it
{       is expired and you will be able to rewrite it on the R1.6.1 release.
{       By default (both in the past and when executing on R1.6.1), the
{       default is to write the tape as expired.
{
{   2.  If you have an operator initialize (blank label) your tape on R1.6.1,
{       be advised that NOS/VE writes your user name in the label when you
{       first write on a blank labeled tape.  Thereafter, if your site chooses
{       to enable security, you are the only user who can access the volume.
{       If you intend to have other users share your tape, you must plan ahead
{       for when security is enabled; read the discussion below.  If your
{       current tape is never initialized in the future, you may continue to
{       access it as before, but so may other users...
{
{
{   3.  When security is enabled, tape users will be affected as follows:
{
{       a.  When ENFORCE_TAPE_SECURITY is in the ON condition, only a
{           Removable Media Administrator (RMA) may access a labeled tape
{           using FILE_LABEL_TYPE=UNLABELED or NON_STANDARD_LABELED.  This may
{           break site-defined procedures that display tape labels or
{           duplicate labeled tapes.  Five new SCL procedures and functions are
{           made available on OSF$SITE_COMMAND_LIBRARY to lessen the impact of
{           the security changes:
{
{           COMPARE_LABELED_VOLUMES - allows a user to compare the data, the
{           labels, or both, on two labeled volumes without violating
{           security.
{
{           COMPARE_UNLABELED_VOLUMES - allows a user to compare the contents
{           of two unlabeled volumes.  This function requires the user to be
{           validated for UNLABELED_TAPES for READ access.
{
{           DISPLAY_FILE_SET_ATTRIBUTES - allows a user to display the header
{           labels, trailer labels, or individual fields from all or a subset
{           of the ANSI files in a file set.  For example,
{
{          /reqmt $local.t rvsn=atape r=no d=mt9$6250
{          /disfsa $local.t do=(fi cd ed rt bt maxbl)
{
{           Display_file_set_attributes for file :$LOCAL.T
{
{
{          1
{            Block_Type           : user_specified
{            Creation_Date        : 1991-07-24
{            Expiration_Date      : 1991-07-24
{            File_Identifier      : 'IDC_16           '
{            Maximum_Block_Length : 4128
{            Record_Type          : undefined
{          2
{            Block_Type           : user_specified
{            Creation_Date        : 1991-07-24
{            Expiration_Date      : 1991-07-24
{            File_Identifier      : 'SCI_12           '
{            Maximum_Block_Length : 4128
{            Record_Type          : undefined
{
{           DUPLICATE_LABELED_VOLUME - allows a user to create a duplicate of
{           a labeled volume without violating security.
{
{           DUPLICATE_UNLABELED_VOLUME - allows a user who is validated for
{           UNLABELED_VOLUMES for (READ, WRITE) to duplicate an unlabeled
{           volume.
{
{       b.  If your tape is unlabeled, you must be validated for the
{           UNLABELED_TAPES Removable Media Access.  You may be validated for
{           READ, WRITE, or both.  You will no longer be able to access a
{           labeled tape using a FILE_LABEL_TYPE of UNLABELED.  Only a user
{           executing within the SYSTEM_OPERATOR_UTILITY with the
{           REMOVABLE_MEDIA_ADMINISTRATION capability active is given this
{           privilege.
{
{       c.  If your tape is labeled but written by another CDC system (NOS,
{           NOS/BE, EP/IX, SCOPE 2) or by other vendor's system (IBM, CRAY,
{           DEC, etc.), you must be validated for the LABELED_EXTERNAL_TAPES
{           Removable Media Access.  You may be validated for READ, WRITE, or
{           both.  WRITE access only allows the creation of a new file at the
{           end of the file set.
{
{   4.  NOS/VE's release materials are labeled for the RELEASE_TAPES Removable
{       Media Access.  Anyone using the tapes in conjuction with deadstart
{       does not require validation.  However, if you access release tapes in
{       other contexts (e.g.  using MAIDS), you must be validated for
{       RELEASE_TAPES.
{
{   5.  If you share your tape with other people and you have your tape
{       initialized (blank labeled) on R1.6.1, you have the following options
{       when you first write on the tape:
{
{        - You may make your tape PUBLIC (available to everyone) by using the
{          CHANGE_TAPE_LABEL_ATTRIBUTES (CHATLA) command to set the Volume
{          Accessibility (VA) to SPACE:
{
{            reqmt $local.t recorded_vsn=VE126 ring=true t=mt9$6250
{            change_tape_label_attributes $local.t va=none
{            bacpf bf=$local.t
{
{          NOTE:  You will need to specify VA=NONE each time you do a BACPF at
{          beginning of volume or whenever you specify REWRITE_LABELS=TRUE.
{
{       - You may invent a group name (13 characters or less) and ask that
{         those who need to share the volume be validated for the Removable
{         Media Access group.  Each group member may be given their own access
{         for READ, WRITE, or both.  When you first write the tape, specify
{         the group name.  In the following example, RELEASE_TAPES is the
{         group name:
{
{            reqmt $local.t recorded_vsn=VE126 ring=true t=mt9$6250
{            change_tape_label_attributes $local.t ..
{               removable_media_group=release_tapes
{            bacpf bf=$local.t
{
{        - You may password protect the tape by specifying one or more of the
{          security fields.  VA must be set to a value other than 'A'.  On
{          subsequent tape requests, you must repeat the specification of the
{          security field, or access is denied.  This is a less secure and less
{          formal way to share the tape.  Any user who knows the password can
{          gain access.  In the following example, the values B and PROJECT_X
{          are used as passwords when writing the tape:
{
{            reqmt $local.t recorded_vsn=VE126 ring=true t=mt9$6250
{            change_tape_label_attributes $local.t fa=b oi=project_x va=none
{            bacpf bf=$local.t
{
{          NOTE: When using the tape in a future job you must specify the
{          passwords again:
{
{            reqmt $local.t recorded_vsn=VE126 ring=true t=mt9$6250
{            change_tape_label_attributes $local.t fa=b oi=project_x
{            bacpf bf=$local.t
{
{        - If you choose none of the above, your tape will be private to you, by
{          default.  If you want someone else to share the tape, you may
{          catalog it and permit others to use it or you can have the operator
{          blank label it again so you can try one of the preceding options.
{          To catalog it do the following:
{
{          REQMT $user.ve126 recorded_vsn=VE126 ring=true t=mt9$6250
{          CREATE_FILE_PERMIT $user.ve126 g=user u=fred am=(read)
{          CREATE_FILE_PERMIT $user.ve126 g=user u=karen am=(read, write)
{
{   6.  If you initialize your tape on R1.6.1 and then label it for yourself
{       as the owner or label it for a group, you should avoid writing that
{       tape on a previous NOS/VE release, particularly if you specify
{       REWRITE_LABELS=TRUE or use BACPF (which forces REWRITE_LABELS=TRUE).
{       If you do this, you must specify VA=A and OI=user or OI='&group' when
{       you access the tape again on the R1.6.1 NOS/VE release.  The VA and OI
{       parameters must be specified on the CHANGE_TAPE_LABEL_ATTRIBUTES
{       command.
?? OLDTITLE ??
?? NEWTITLE := 'Global Variables Declared by This Module', EJECT ??

  CONST
    epix_version_one = 'EP/IX V1.0   ';

  VAR
    log_labels: boolean,
    omit_strict_hdr1_checking: boolean,
    ve_character_conversions: [STATIC, READ, oss$job_paged_literal] set of char := ['F', 'T', 'f', 't', ' '
          {allow SPACE for initialized (blank) volume} ],

    ve_character_sets: [STATIC, READ, oss$job_paged_literal] set of char := ['A', 'E', 'a', 'e', ' '
          {allow SPACE for initialized (blank) volume} ],

    ve_record_types: [STATIC, READ, oss$job_paged_literal] set of char := ['D', 'F', 'S', 'U', 'V', 'd', 'f',
          's', 'u', 'v', ' '
          {allow SPACE for initialized (blank) volume} ];

?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
*copyc clt$string_value
*copyc fst$ansi_eof1_label
*copyc fst$ansi_eof2_label
*copyc fst$ansi_eofn_label
*copyc fst$ansi_eov1_label
*copyc fst$ansi_eov2_label
*copyc fst$ansi_eovn_label
*copyc fst$ansi_hdr1_label
*copyc fst$ansi_hdr2_label
*copyc fst$ansi_hdrn_label
*copyc fst$ansi_uhla_label
*copyc fst$ansi_utla_label
*copyc fst$ansi_uvln_label
*copyc fst$ansi_vol1_label
*copyc fst$ansi_voln_label
*copyc fst$tape_security_call_block
*copyc rmt$tape_volume_classification
?? PUSH (LISTEXT := ON) ??
*copyc ame$label_validation_errors
*copyc ame$tape_program_actions
*copyc cle$ecc_expression_result
*copyc fst$file_access_options
*copyc oss$job_paged_literal
*copyc rmc$labeled_external_tapes
*copyc rmc$unlabeled_tapes
*copyc rmc$vol_classification_module
*copyc rmc$vol_classification_prompt
?? POP ??
*copyc amp$access_method
*copyc avp$get_removable_media_access
*copyc avp$removable_media_admin
*copyc avp$removable_media_operator
*copyc clp$convert_string_to_date_time
*copyc clp$convert_string_to_integer
*copyc clp$get_variable
*copyc clp$trimmed_string_size
*copyc fsp$analyze_file_expiration
*copyc fsp$get_tape_label_attributes
*copyc fsp$locate_tape_label
*copyc fsp$version_one_tape_label
*copyc fsp$version_two_tape_label
*copyc fsp$ve_wrote_ansi_file
*copyc osp$find_help_module
*copyc osp$find_parameter_prompt
*copyc osp$format_help_message
*copyc osp$generate_error_message
*copyc osp$generate_log_message
*copyc osp$set_status_abnormal
*copyc osp$set_status_condition
*copyc osp$append_status_file
*copyc osp$append_status_integer
*copyc osp$append_status_parameter
*copyc pmp$get_user_identification
*copyc pmp$get_account_project
*copyc osv$lower_to_upper
?? EJECT ??
?? OLDTITLE ??
?? NEWTITLE := 'rmp$classify_tape_volume', EJECT ??
*copyc rmh$classify_tape_volume
?? EJECT ??

  PROCEDURE [#GATE, XDCL] rmp$classify_tape_volume
    (    read_labels_status: ost$status;
         volume_header_labels: ^SEQ ( * );
     VAR volume_classification: rmt$tape_volume_classification;
     VAR status: ost$status);

    VAR
      hdr1_label: ^fst$ansi_hdr1_label,
      hdr2_label: ^fst$ansi_hdr2_label,
      version_one_blank: boolean,
      vol1_label: ^fst$ansi_vol1_label;

    status.normal := TRUE;

    locate_labels (volume_header_labels, vol1_label, hdr1_label, hdr2_label);
    IF read_labels_status.normal THEN
      IF (vol1_label <> NIL) THEN
        volume_classification.volume_label_type := rmc$labeled_volume_type;
        volume_classification.labeled.volume_identifier := vol1_label^.volume_identifier;
        determine_blank_labeled_status (vol1_label^, hdr1_label, hdr2_label,
              volume_classification.labeled.blank, version_one_blank, status);
        IF status.normal THEN
          analyze_volume_security (vol1_label^, hdr1_label, hdr2_label, version_one_blank,
                volume_classification.labeled, status);
        IFEND;
      ELSE
        volume_classification.volume_label_type := rmc$labeled_volume_type;
        volume_classification.labeled.volume_security_type := rmc$vst_access_restricted;
        volume_classification.labeled.reason := rmc$vol1_missing;
      IFEND;
    ELSE
      CASE read_labels_status.condition OF
      = ame$excessive_tape_labels =
        volume_classification.volume_label_type := rmc$labeled_volume_type;
        volume_classification.labeled.volume_security_type := rmc$vst_access_restricted;
        volume_classification.labeled.reason := rmc$excessive_tape_labels;
        volume_classification.labeled.blank := FALSE;
        volume_classification.labeled.expired := FALSE;

      = ame$invalid_tape_label =
        volume_classification.volume_label_type := rmc$unlabeled_volume_type;
        volume_classification.blank := FALSE;

      = ame$unexpected_tapemark =
        volume_classification.volume_label_type := rmc$unlabeled_volume_type;
        volume_classification.blank := TRUE;

      = ame$unexpected_tape_label =
        volume_classification.volume_label_type := rmc$labeled_volume_type;
        volume_classification.labeled.volume_security_type := rmc$vst_access_restricted;
        volume_classification.labeled.reason := rmc$vol1_missing;
        volume_classification.labeled.blank := FALSE;
        volume_classification.labeled.expired := FALSE;

      = ame$tape_label_read_error =
        volume_classification.volume_label_type := rmc$indeterminate_volume_type;
      ELSE
        status := read_labels_status;
      CASEND;
    IFEND;
    IF status.normal THEN
      IF (volume_classification.volume_label_type = rmc$labeled_volume_type) AND
            (volume_classification.labeled.volume_security_type = rmc$vst_access_restricted) THEN
        IF vol1_label <> NIL THEN
          volume_classification.labeled.volume_accessibility := vol1_label^.accessibility;
          volume_classification.labeled.volume_identifier := vol1_label^.volume_identifier;
        ELSE
          volume_classification.labeled.volume_accessibility := ' ';
          volume_classification.labeled.volume_identifier := '      ';
        IFEND;
        IF hdr1_label <> NIL THEN
          volume_classification.labeled.file_accessibility := hdr1_label^.accessibility;
          volume_classification.labeled.implementation_identifier := hdr1_label^.system_code;
        ELSE
          volume_classification.labeled.file_accessibility := ' ';
          volume_classification.labeled.implementation_identifier := '              ';
        IFEND;
      IFEND;
    IFEND;
  PROCEND rmp$classify_tape_volume;
?? OLDTITLE ??
?? NEWTITLE := '  analyze_volume_security', EJECT ??

  PROCEDURE analyze_volume_security
    (    vol1_label: fst$ansi_vol1_label;
         hdr1_label: ^fst$ansi_hdr1_label;
         hdr2_label: ^fst$ansi_hdr2_label;
         version_one_blank: boolean;
     VAR labeled_tape_classification {input, output} : rmt$labeled_tape_classification;
     VAR status: ost$status);

  VAR
    local_status: ost$status;

    status.normal := TRUE;
    labeled_tape_classification.expired := FALSE;
    labeled_tape_classification.file_accessibility := ' ';
    labeled_tape_classification.implementation_identifier := ' ';
    labeled_tape_classification.volume_accessibility := vol1_label.accessibility;
    labeled_tape_classification.volume_identifier := vol1_label.volume_identifier;
    IF hdr1_label = NIL THEN
      labeled_tape_classification.volume_security_type := rmc$vst_access_restricted;
      labeled_tape_classification.reason := rmc$hdr1_missing;
      IF labeled_tape_classification.blank THEN
        labeled_tape_classification.expired := TRUE;
      IFEND;
    ELSE
      fsp$analyze_file_expiration (hdr1_label^.expiration_date, labeled_tape_classification.expired,
            local_status);
      IF NOT local_status.normal THEN
        labeled_tape_classification.expired := TRUE;
      IFEND;
      labeled_tape_classification.file_accessibility := hdr1_label^.accessibility;
      labeled_tape_classification.implementation_identifier := hdr1_label^.system_code;

      IF fsp$ve_wrote_ansi_file (hdr1_label^.system_code) THEN
        IF fsp$version_two_tape_label (hdr1_label^.system_code) AND
              (vol1_label.accessibility = 'A') THEN
          IF vol1_label.owner_identifier (1) = '&' THEN
            labeled_tape_classification.volume_security_type := rmc$vst_ve_labeled_for_group;
            labeled_tape_classification.removable_media_group := vol1_label.owner_identifier (2, 13);
          ELSE
            labeled_tape_classification.volume_security_type := rmc$vst_ve_labeled_for_user;
            labeled_tape_classification.user := vol1_label.owner_identifier;
          IFEND;
        ELSE
          labeled_tape_classification.volume_security_type := rmc$vst_ve_password_protected;
          labeled_tape_classification.ve_owner_identifier := vol1_label.owner_identifier;
        IFEND;
      ELSEIF version_one_blank THEN
        {Change classification if the blank label group could have been written by pre-L780 NOS/VE
        {Refer to DETERMINE_BLANK_LABELED_STATUS for more information.
        labeled_tape_classification.implementation_identifier := fsc$version_one_ve_identifier;
        labeled_tape_classification.volume_security_type := rmc$vst_ve_password_protected;
        labeled_tape_classification.ve_owner_identifier := vol1_label.owner_identifier;
      ELSE
        labeled_tape_classification.volume_security_type := rmc$vst_labeled_external;
        labeled_tape_classification.external_owner_identifier := vol1_label.owner_identifier;
      IFEND;
    IFEND;
  PROCEND analyze_volume_security;
?? OLDTITLE ??
?? NEWTITLE := '  determine_blank_labeled_status', EJECT ??

  PROCEDURE determine_blank_labeled_status
    (    vol1_label: fst$ansi_vol1_label;
         hdr1_label: ^fst$ansi_hdr1_label;
         hdr2_label: ^fst$ansi_hdr2_label;
     VAR blank_labeled: boolean;
     VAR version_one_blank: boolean;
     VAR status: ost$status);

    VAR
      file_is_expired: boolean,
      local_status: ost$status;

    status.normal := TRUE;
    blank_labeled := FALSE;
    version_one_blank := FALSE;

    IF (hdr1_label = NIL) THEN
      IF (hdr2_label = NIL) THEN
        blank_labeled := TRUE;
      IFEND;
    ELSEIF fsp$ve_wrote_ansi_file (hdr1_label^.system_code) THEN
      fsp$analyze_file_expiration (hdr1_label^.expiration_date, file_is_expired, local_status);
      IF NOT local_status.normal THEN
        file_is_expired := TRUE;
      IFEND;
      IF file_is_expired AND (hdr2_label <> NIL) THEN
        IF (hdr2_label^.ve_block_type = ' ') AND (hdr2_label^.ve_record_type = ' ') AND
              (hdr2_label^.ve_block_length_ext = ' ') AND (hdr2_label^.ve_record_length_ext = ' ') AND
              (hdr2_label^.ve_padding_character = ' ') AND (hdr2_label^.ve_character_set = ' ') AND
              (hdr2_label^.ve_character_conversion = ' ') AND (hdr2_label^.ve_reserved = ' ') THEN
          blank_labeled := TRUE;
        IFEND;
      IFEND;
    ELSEIF (vol1_label.accessibility = ' ') AND (vol1_label.owner_identifier = ' ') AND
          (hdr1_label^.system_code = ' ') AND (hdr1_label^.accessibility = ' ') THEN
      fsp$analyze_file_expiration (hdr1_label^.expiration_date, file_is_expired, local_status);
      IF NOT local_status.normal THEN
        file_is_expired := TRUE;
      IFEND;
      IF file_is_expired AND (hdr2_label <> NIL) THEN
        IF (hdr2_label^.record_format = ' ') AND (hdr2_label^.block_length = '00000') AND
              (hdr2_label^.record_length = '00000') AND (hdr2_label^.ve_block_type = ' ') AND
              (hdr2_label^.ve_record_type = ' ') AND (hdr2_label^.ve_block_length_ext = '000') AND
              (hdr2_label^.ve_record_length_ext = '000') AND (hdr2_label^.ve_padding_character = ' ') AND
              (hdr2_label^.ve_character_set = ' ') AND (hdr2_label^.ve_character_conversion = ' ') THEN
              {A tape written by NOS/VE prior to L780 (R1.6.1) may have a blank label group at BOS but
              {have files beyond the first one.
          version_one_blank := TRUE;
        ELSEIF (hdr2_label^.record_format = ' ') THEN
          blank_labeled := TRUE;
        IFEND;
      IFEND;
    IFEND;

  PROCEND determine_blank_labeled_status;
?? OLDTITLE ??
?? NEWTITLE := '  locate_labels', EJECT ??

  PROCEDURE locate_labels
    (    volume_header_labels: ^SEQ ( * );
     VAR vol1_label: ^fst$ansi_vol1_label;
     VAR hdr1_label: ^fst$ansi_hdr1_label;
     VAR hdr2_label: ^fst$ansi_hdr2_label);

    VAR
      label_identifier: fst$tape_label_identifier,
      label_locator: fst$tape_label_locator;

    label_identifier.location_method := fsc$tape_label_locate_by_kind;
    label_identifier.label_kind := fsc$ansi_vol1_label_kind;
    fsp$locate_tape_label (volume_header_labels, label_identifier, label_locator);
    IF label_locator.label_found THEN
      RESET label_locator.label_block;
      NEXT vol1_label IN label_locator.label_block;
    ELSE
      vol1_label := NIL;
    IFEND;

    label_identifier.location_method := fsc$tape_label_locate_by_kind;
    label_identifier.label_kind := fsc$ansi_hdr1_label_kind;
    fsp$locate_tape_label (volume_header_labels, label_identifier, label_locator);
    IF label_locator.label_found THEN
      RESET label_locator.label_block;
      NEXT hdr1_label IN label_locator.label_block;
    ELSE
      hdr1_label := NIL;
    IFEND;

    label_identifier.location_method := fsc$tape_label_locate_by_kind;
    label_identifier.label_kind := fsc$ansi_hdr2_label_kind;
    fsp$locate_tape_label (volume_header_labels, label_identifier, label_locator);
    IF label_locator.label_found THEN
      RESET label_locator.label_block;
      NEXT hdr2_label IN label_locator.label_block;
    ELSE
      hdr2_label := NIL;
    IFEND;

  PROCEND locate_labels;
?? OLDTITLE ??
?? NEWTITLE := 'rmp$format_vol_classification', EJECT ??
*copyc rmh$format_vol_classification
  PROCEDURE [#GATE, XDCL] rmp$format_vol_classification
    (    max_message_line: ost$max_status_message_line;
         volume_classification: rmt$tape_volume_classification;
     VAR formatted_classification: ost$status_message;
     VAR status: ost$status);

    CONST
      access_restricted = ', Access Restricted due to ',
      blank = ', Blank',
      cdc_version_one = ', CDC_VERSION_ONE',
      cdc_version_two = ', CDC_VERSION_TWO',
      comma = ', ',
      excessive_tape_labels = 'Excessive Tape Labels',
      expired = ', Expired',
      external = ', External',
      external_required = 'validated for LABELED_EXTERNAL_TAPES Removable Media Access ',
      file_accessibility = 'File Accessibility: ',
      for_group = ' for Group',
      for_user = ' for User',
      hdr1_missing = 'Missing HDR1 Label',
      indeterminate = 'Indeterminate',
      labeled = 'Labeled',
      nonblank = ', Nonblank',
      owner_identifier = 'Owner Identifier: ',
      password_protected = ', Password Protected',
      public = ', Public',
      rma_required = 'a Removable Media Administrator ',
      space = ' ',
      to_access = 'to access the volume.',
      ul_or_nsl_access =
            'You must specify a FILE_LABEL_TYPE of UNLABELED or NON_STANDARD_LABELED to access the volume.',
      unexpired = ', Unexpired',
      unlabeled = 'Unlabeled',
      unlabeled_required = 'validated for UNLABELED_TAPES Removable Media Access ',
      vol1_missing = 'Missing VOL1 Label',
      volume_accessibility = 'Volume Accessibility: ',
      volume_classification_text = 'Volume Classification: ',
      when_enabled = 'When security is enabled, you must be ';

    VAR
      current_column_number: 0 .. 255,
      current_parameter_number: 1 .. 3,
      params: array [1 .. 3] of ^string ( * ),
      p1: ^string ( * ),
      p2: ^string ( * ),
      p3: ^string ( * ),
      size: 0 .. 14;

?? NEWTITLE := '  append_security_fields', EJECT ??

    PROCEDURE append_security_fields;

      VAR
        next_param: 1 .. 3;

      next_param := current_parameter_number + 1;
      current_parameter_number := next_param;
      current_column_number := 1;

      IF volume_classification.labeled.file_accessibility <> space THEN
        append_string (next_param, file_accessibility);
        append_string (next_param, volume_classification.labeled.file_accessibility);
      IFEND;

      CASE volume_classification.labeled.volume_security_type OF
      = rmc$vst_labeled_external =
        IF volume_classification.labeled.external_owner_identifier <> space THEN
          IF current_column_number > 1 THEN
            append_string (next_param, comma);
          IFEND;
          append_string (next_param, owner_identifier);
          size := clp$trimmed_string_size(volume_classification.labeled.external_owner_identifier);
          append_string (next_param, volume_classification.labeled.external_owner_identifier (1, size));
        IFEND;
        IF volume_classification.labeled.volume_accessibility <> space THEN
          IF current_column_number > 1 THEN
            append_string (next_param, comma);
          IFEND;
          append_string (next_param, volume_accessibility);
          append_string (next_param, volume_classification.labeled.volume_accessibility);
        IFEND;

      = rmc$vst_ve_password_protected =
        IF volume_classification.labeled.ve_owner_identifier <> space THEN
          IF current_column_number > 1 THEN
            append_string (next_param, comma);
          IFEND;
          append_string (next_param, owner_identifier);
          size := clp$trimmed_string_size(volume_classification.labeled.ve_owner_identifier);
          append_string (next_param, volume_classification.labeled.ve_owner_identifier (1, size));
        IFEND;
        IF volume_classification.labeled.volume_accessibility <> space THEN
          IF current_column_number > 1 THEN
            append_string (next_param, comma);
          IFEND;
          append_string (next_param, volume_accessibility);
          append_string (next_param, volume_classification.labeled.volume_accessibility);
        IFEND;
      ELSE
      CASEND;
    PROCEND append_security_fields;
?? OLDTITLE ??
?? NEWTITLE := '  append_string', EJECT ??

    PROCEDURE append_string
      (    parameter_number: 1 .. 3;
           text: string ( * ));

      IF current_parameter_number <> parameter_number THEN
        current_column_number := 1;
        current_parameter_number := parameter_number;
      IFEND;

      params [current_parameter_number]^ (current_column_number, STRLENGTH (text)) :=
            text (1, STRLENGTH (text));
      current_column_number := current_column_number + STRLENGTH (text);

    PROCEND append_string;
?? OLDTITLE, EJECT ??
  VAR
    help_module: ^ost$help_module,
    ignore_natural_language: ost$natural_language,
    ignore_online_manual_name: ost$online_manual_name,
    message_template: ^ost$message_template;

    status.normal := TRUE;

    PUSH p1: [osc$status_message_width];
    PUSH p2: [osc$status_message_width];
    PUSH p3: [osc$status_message_width];

    params [1] := p1;
    params [2] := p2;
    params [3] := p3;

    p1^ := space;
    p2^ := space;
    p3^ := space;

    current_column_number := 1;
    current_parameter_number := 1;
    append_string (1, volume_classification_text);

    CASE volume_classification.volume_label_type OF
    = rmc$indeterminate_volume_type =
      append_string (1, indeterminate);
      IF NOT avp$removable_media_admin () THEN
        append_string (2, when_enabled);
        append_string (2, rma_required);
        append_string (2, to_access);
      IFEND;
    = rmc$labeled_volume_type =
      append_string (1, labeled);
      CASE volume_classification.labeled.volume_security_type OF
      = rmc$vst_access_restricted =
        IF volume_classification.labeled.blank THEN
          append_string (1, blank);
        ELSE
          append_string (1, nonblank);
        IFEND;
        IF volume_classification.labeled.expired THEN
          append_string (1, expired);
        ELSE
          append_string (1, unexpired);
        IFEND;
        append_string (1, access_restricted);
        CASE volume_classification.labeled.reason OF
        = rmc$excessive_tape_labels =
          append_string (1, excessive_tape_labels);
        = rmc$hdr1_missing =
          append_string (1, hdr1_missing);
        = rmc$vol1_missing =
          append_string (1, vol1_missing);
        ELSE
        CASEND;
        IF avp$removable_media_admin () THEN
          append_string (2, ul_or_nsl_access);
        ELSE
          append_string (2, when_enabled);
          append_string (2, rma_required);
          append_string (2, to_access);
        IFEND;
      = rmc$vst_labeled_external =
        append_string (1, external);
        IF volume_classification.labeled.blank THEN
          append_string (1, blank);
        ELSE
          append_string (1, nonblank);
        IFEND;
        IF volume_classification.labeled.expired THEN
          append_string (1, expired);
        ELSE
          append_string (1, unexpired);
        IFEND;
        IF (volume_classification.labeled.file_accessibility <> space) OR
              (volume_classification.labeled.external_owner_identifier <> space) OR
              (volume_classification.labeled.volume_accessibility <> space) THEN
          append_string (1, password_protected);
        ELSE
          append_string (1, public);
        IFEND;
        IF NOT avp$removable_media_admin () THEN
          append_string (2, when_enabled);
          append_string (2, external_required);
          append_string (2, to_access);
        IFEND;
      = rmc$vst_ve_labeled_for_group =
        append_string (1, for_group);
        size := clp$trimmed_string_size(volume_classification.labeled.removable_media_group);
        IF size > 0 THEN
          append_string (1, space);
          append_string (1, volume_classification.labeled.removable_media_group (1, size));
        IFEND;
        IF volume_classification.labeled.blank THEN
          append_string (1, blank);
        ELSE
          append_string (1, nonblank);
        IFEND;
        IF volume_classification.labeled.expired THEN
          append_string (1, expired);
        ELSE
          append_string (1, unexpired);
        IFEND;
        IF (volume_classification.labeled.file_accessibility <> space) THEN
          append_string (1, password_protected);
        IFEND;
      = rmc$vst_ve_labeled_for_user =
        append_string (1, for_user);
        size := clp$trimmed_string_size(volume_classification.labeled.user);
        IF size > 0 THEN
          append_string (1, space);
          append_string (1, volume_classification.labeled.user (1, size));
        IFEND;
        IF volume_classification.labeled.blank THEN
          append_string (1, blank);
        ELSE
          append_string (1, nonblank);
        IFEND;
        IF volume_classification.labeled.expired THEN
          append_string (1, expired);
        ELSE
          append_string (1, unexpired);
        IFEND;
        IF (volume_classification.labeled.file_accessibility <> space) THEN
          append_string (1, password_protected);
        IFEND;
      = rmc$vst_ve_password_protected =
        IF fsp$version_one_tape_label (volume_classification.labeled.implementation_identifier) THEN
          append_string (1, cdc_version_one);
        ELSEIF fsp$version_two_tape_label (volume_classification.labeled.implementation_identifier) THEN
          append_string (1, cdc_version_two);
        IFEND;
        IF volume_classification.labeled.blank THEN
          append_string (1, blank);
        ELSE
          append_string (1, nonblank);
        IFEND;
        IF volume_classification.labeled.expired THEN
          append_string (1, expired);
        ELSE
          append_string (1, unexpired);
        IFEND;
        IF (volume_classification.labeled.file_accessibility <> space) OR
              (volume_classification.labeled.ve_owner_identifier <> space) OR
              (volume_classification.labeled.volume_accessibility <> space) THEN
          append_string (1, password_protected);
        ELSE
          append_string (1, public);
        IFEND;
      ELSE
      CASEND;
      append_security_fields;

    = rmc$unlabeled_volume_type =
      append_string (1, unlabeled);
      IF volume_classification.blank THEN
        append_string (1, blank);
      ELSE
        append_string (1, nonblank);
      IFEND;
      IF NOT avp$removable_media_admin () THEN
        append_string (2, when_enabled);
        append_string (2, unlabeled_required);
        append_string (2, to_access);
      IFEND;
    ELSE
    CASEND;

    osp$find_help_module (rmc$vol_classification_module, help_module, ignore_online_manual_name,
          ignore_natural_language, status);
    IF status.normal THEN
      osp$find_parameter_prompt (help_module, rmc$vol_classification_prompt, message_template, status);
      IF status.normal THEN
        osp$format_help_message (message_template, ^params, max_message_line, formatted_classification,
              status);
      IFEND;
    IFEND;

  PROCEND rmp$format_vol_classification;
?? OLDTITLE ??
?? NEWTITLE := 'rmp$validate_ansi_string', EJECT ??

  PROCEDURE [#GATE, XDCL] rmp$validate_ansi_string (
        input_string: clt$string_value;
    VAR validated_string: clt$string_value;
    VAR status: ost$status);

    VAR
      i: integer,
      valid_characters: [STATIC, READ, oss$job_paged_literal] set of char := ['A',
        'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
        'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c',
        'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
        'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4',
        '5', '6', '7', '8', '9', ' ', '!', '"', '%', '&', '''', '(', ')', '*',
        '+', '-', '.', '/', ':', ';', '<', '=', '>', '?', '_', '$', '#', '@'];

    status.normal := TRUE;

    FOR i := 1 TO clp$trimmed_string_size (input_string) DO
      IF NOT (input_string (i) IN valid_characters) THEN
        osp$set_status_abnormal ('CL', cle$name_not_a_keyword_value, input_string, status);
        RETURN;
      IFEND;
    FOREND;

{ Convert all characters to upper case.

    #translate (osv$lower_to_upper, input_string, validated_string);

  PROCEND rmp$validate_ansi_string;
?? OLDTITLE ??
?? NEWTITLE := 'rmp$enforce_tape_security', EJECT ??
*copyc rmh$enforce_tape_security
?? EJECT ??

  PROCEDURE [XDCL] rmp$enforce_tape_security
    (    file_identifier: amt$file_identifier;
         call_block: amt$call_block;
         layer_number: amt$fap_layer_number;
     VAR status: ost$status);

    VAR
      account: avt$account_name,
      family: ost$family_name,
      local_status: ost$status,
      project: avt$project_name,
      user: ost$user_name;

    status.normal := TRUE;

  /main_program/
    BEGIN

      CASE call_block.operation OF

      = amc$dismount_current_volume =
        amp$access_method (file_identifier, call_block, layer_number, status);

      = amc$enforce_tape_security =
        enforce_tape_security (file_identifier, call_block, layer_number, status);

      = amc$fetch_req =
        amp$access_method (file_identifier, call_block, layer_number, status);

      = amc$fetch_access_information_rq =
        amp$access_method (file_identifier, call_block, layer_number, status);

      = amc$open_tape_volume =
        get_login_identification (account, family, project, user, local_status);
        IF local_status.normal THEN
          call_block.open_tape_volume^.account := account;
          call_block.open_tape_volume^.family := family;
          call_block.open_tape_volume^.project := project;
          call_block.open_tape_volume^.user := user;
        IFEND;
        amp$access_method (file_identifier, call_block, layer_number, status);

      = amc$read_tape_labels =
        amp$access_method (file_identifier, call_block, layer_number, status);

      = amc$skip_req =
        amp$access_method (file_identifier, call_block, layer_number, status);

      = amc$terminate_tape_volume =
        amp$access_method (file_identifier, call_block, layer_number, status);

      = amc$write_tape_labels =
        amp$access_method (file_identifier, call_block, layer_number, status);

      ELSE

        amp$access_method (file_identifier, call_block, layer_number, status);

      CASEND;

    END /main_program/;

  PROCEND rmp$enforce_tape_security;
?? NEWTITLE := '  enforce_tape_security', EJECT ??

  PROCEDURE enforce_tape_security
    (    file_identifier: amt$file_identifier;
         call_block: amt$call_block;
         layer_number: amt$fap_layer_number;
     VAR status: ost$status);

    VAR
      call_block_p: ^SEQ ( * ),
      fetch_attribute: array [1 .. 1] of amt$fetch_item,
      file: fst$path,
      info_attribute: array [1 .. 1] of amt$access_info,
      local_call_block: amt$call_block,
      resolved_file_reference: fst$resolved_file_reference,
      tape_security_call_block: ^fst$tape_security_call_block,
      volume_number: amt$volume_number;

    status.normal := TRUE;

    local_call_block.operation := amc$fetch_req;
    fetch_attribute [1].key := amc$resolved_file_reference;
    fetch_attribute [1].resolved_file_reference := ^resolved_file_reference;
    local_call_block.fetch.file_attributes := ^fetch_attribute;
    amp$access_method (file_identifier, local_call_block, layer_number, status);

    IF status.normal THEN
      local_call_block.operation := amc$fetch_access_information_rq;
      info_attribute [1].key := amc$volume_number;
      local_call_block.fai.access_information := ^info_attribute;
      amp$access_method (file_identifier, local_call_block, layer_number, status);
      IF status.normal THEN
        volume_number := info_attribute [1].volume_number;
        info_attribute [1].key := amc$volume_description;
        info_attribute [1].volume_index := volume_number;
        local_call_block.fai.access_information := ^info_attribute;
        amp$access_method (file_identifier, local_call_block, layer_number, status);
      IFEND;
    IFEND;

    IF status.normal THEN
      file := resolved_file_reference.path (1, resolved_file_reference.cycle_path_size);
      call_block_p := call_block.enforce_tape_security;
      RESET call_block_p;
      NEXT tape_security_call_block IN call_block_p;
      IF tape_security_call_block <> NIL THEN
        get_boolean_variable ('rmv$log_ansi_labels', log_labels);
        CASE tape_security_call_block^.operation OF
        = fsc$ts_authorize_access_method =
          authorize_access_method (resolved_file_reference, file_identifier,
                tape_security_call_block^.authorize_access_method, layer_number, status);

        = fsc$ts_authorize_file_access =
          authorize_file_access (resolved_file_reference, file_identifier,
                tape_security_call_block^.authorize_file_access, layer_number,
                info_attribute [1].volume_description, status);

        = fsc$ts_authorize_file_reuse =
          authorize_file_reuse (file, file_identifier, tape_security_call_block^.authorize_file_reuse,
                layer_number, info_attribute [1].volume_description, status);

        = fsc$ts_authorize_section_read =
          authorize_section_read (resolved_file_reference, file_identifier,
                tape_security_call_block^.authorize_section_read, layer_number,
                info_attribute [1].volume_description, status);

        = fsc$ts_authorize_section_write =
          authorize_section_write (file, file_identifier, tape_security_call_block^.authorize_section_write,
                layer_number, info_attribute [1].volume_description, status);

        = fsc$ts_authorize_file_set_mount =
          authorize_file_set_mount (resolved_file_reference, file_identifier,
                tape_security_call_block^.authorize_file_set_mount, layer_number,
                info_attribute [1].volume_description, status);

        = fsc$ts_authorize_file_set_reuse =
          authorize_file_set_reuse (resolved_file_reference, file_identifier,
                tape_security_call_block^.authorize_file_set_reuse, layer_number,
                info_attribute [1].volume_description, status);

        = fsc$ts_authorize_volume_reuse =
          authorize_volume_reuse (file, file_identifier, tape_security_call_block^.authorize_volume_reuse,
                layer_number, status);

        = fsc$ts_secure_header_labels =
          secure_header_labels (file, file_identifier, tape_security_call_block^.secure_header_labels,
                layer_number, status);

        = fsc$ts_secure_trailer_labels =
          secure_trailer_labels (file, file_identifier, tape_security_call_block^.secure_trailer_labels,
                layer_number, status);

        = fsc$ts_validate_header_labels =
          validate_header_labels (file, file_identifier, tape_security_call_block^.validate_header_labels,
                layer_number, status);

        = fsc$ts_validate_trailer_labels =
          validate_trailer_labels (file, file_identifier, tape_security_call_block^.validate_trailer_labels,
                layer_number, status);
        ELSE
          osp$set_status_condition (ame$invalid_tape_security_call, status);
          osp$append_status_file (osc$status_parameter_delimiter, file, status);
        CASEND;
      ELSE
        osp$set_status_condition (ame$invalid_tape_security_call, status);
        osp$append_status_file (osc$status_parameter_delimiter, file, status);
      IFEND;
    IFEND;
  PROCEND enforce_tape_security;
?? NEWTITLE := '    authorize_access_method', EJECT ??

  PROCEDURE authorize_access_method
    (    file: fst$resolved_file_reference;
         file_identifier: amt$file_identifier;
         request: fst$ts_authorize_access_method;
         layer_number: amt$fap_layer_number;
     VAR status: ost$status);

{
{    This procedure verifies that the user has the necessary validation to
{ access a volume using either non_standard_labeled or unlabeled access
{ methods.  This prevents the unauthorized user from using
{ FSP$GET_TAPE_LABEL_ATTRIBUTES or other access method interfaces to view
{ labels that may exist on the volume even though data access may later be
{ denied.
{
{    REQUEST parameters:
{
{       access_method (input):  This parameter identifies the access paradigm
{             requested for this instance of open.
{
{       enforce_tape_security (input):  Indicates whether or not tape security
{             is to be enforced.
{
?? EJECT ??

    VAR
      authorized_access: fst$file_access_options,
      family: ost$family_name,
      user: ost$user_name;

    status.normal := TRUE;
    IF request.enforce_tape_security THEN
      IF NOT avp$removable_media_admin () THEN
        CASE request.access_method OF
        = amc$non_standard_labeled =
          osp$set_status_condition (ame$rma_privilege_required, status);
          osp$append_status_file (osc$status_parameter_delimiter, file.path (1, file.file_path_size), status);
        = amc$unlabeled =
          get_user_identification (file, family, user, status);
          IF status.normal THEN
            avp$get_removable_media_access (user, family, rmc$unlabeled_tapes, authorized_access, status);
            IF (NOT status.normal) OR (authorized_access = $fst$file_access_options []) THEN
              osp$set_status_condition (ame$unlabeled_privilege_needed, status);
              osp$append_status_file (osc$status_parameter_delimiter, file.path (1, file.file_path_size),
                    status);
            IFEND;
          IFEND;
        CASEND;
      IFEND;
    IFEND;

  PROCEND authorize_access_method;
?? OLDTITLE ??
?? NEWTITLE := '    authorize_file_access ', EJECT ??

  PROCEDURE authorize_file_access
    (    file: fst$resolved_file_reference;
         file_identifier: amt$file_identifier;
         request: fst$ts_authorize_file_access;
         layer_number: amt$fap_layer_number;
         volume_descriptor: rmt$volume_descriptor;
     VAR status: ost$status);

{
{    This procedure determines the modes of access available to the user for a
{ particular ANSI file.  If the file is expired, WRITE access is allowed.  This
{ procedure is called for each ANSI file in the file set when VOL1 labels are
{ not included in the labels read.
{
{    Enforcement of the expiration date, is peformed regardless of the
{ enforcement of tape security.
{
{    REQUEST parameters:
{
{       enforce_tape_security (input):  Indicates whether or not tape security
{             is to be enforced.
{
{       header_labels (input):  Header label sequence for the current ANSI
{             file.
{
{       proposed_access (input):  Identifies the modes of access currently
{             granted to this ANSI file.  These proposed modes of access have
{             already been constrained by the modes of access authorized when
{             the initial volume of the file set was mounted.  Refer to
{             AUTHORIZE_FILE_SET_MOUNT.
{
{       proposed_access_defaulted (input):  Indicates whether or not the modes
{             of access were explicitly specified for this instance of open.
{
{       authorized_access (output):  Returns the modes of access that are
{             authorized to the user for this instance of open.  If the
{             proposed_access_defaulted, the access returned may be a subset of
{             the originally proposed_access.
{
?? EJECT ??

    VAR
      authorized_access: fst$file_access_options,
      epix_tape: boolean,
      expiration_reduced_access: boolean,
      file_is_expired: boolean,
      hdr1_label: ^fst$ansi_hdr1_label,
      ignore_hdr2_label: ^fst$ansi_hdr2_label,
      ignore_file_set_access: fst$file_access_options,
      ignore_group: string (13),
      ignore_oi: string (14),
      ignore_status: ost$status,
      ignore_va: string (1),
      ignore_vol1_label: ^fst$ansi_vol1_label,
      returned_attributes: fst$tla_returned_attributes,
      specified_fa: string (1);

    status.normal := TRUE;

    locate_labels (request.header_labels, ignore_vol1_label, hdr1_label, ignore_hdr2_label);
    IF hdr1_label <> NIL THEN
      request.authorized_access^ := $fst$file_access_options [];
      fsp$analyze_file_expiration (hdr1_label^.expiration_date, file_is_expired, status);
      IF status.normal THEN
        expiration_reduced_access := FALSE;
        IF file_is_expired THEN
          authorized_access := request.proposed_access;
        ELSE
          authorized_access := request.proposed_access * (-$fst$file_access_options
                [fsc$modify, fsc$shorten]);
          IF authorized_access <> request.proposed_access THEN
            expiration_reduced_access := TRUE;
          IFEND;
        IFEND;

        IF request.enforce_tape_security AND (NOT avp$removable_media_admin ()) THEN
          ignore_file_set_access := $fst$file_access_options [];
          ignore_va := ' ';
          enforce_epix_security (hdr1_label^.accessibility, hdr1_label^.system_code,
               {user_is_owner} FALSE, ignore_va, authorized_access, epix_tape, ignore_file_set_access);
          IF (NOT epix_tape) AND (hdr1_label^.accessibility <> ' ') THEN
            get_explicit_attributes (file, specified_fa, ignore_group, ignore_oi, ignore_va,
                   returned_attributes, status);
            IF status.normal THEN
              IF (NOT (fsc$tape_file_accessibility IN returned_attributes)) OR (specified_fa  <>
                    hdr1_label^.accessibility) THEN
                 authorized_access := $fst$file_access_options [];
              IFEND;
            IFEND;
          IFEND;
        IFEND;

        IF request.proposed_access_defaulted THEN
          request.authorized_access^ := authorized_access;
        ELSE
          IF authorized_access = request.proposed_access THEN
            request.authorized_access^ := request.proposed_access;
          IFEND;
        IFEND;
        IF (request.authorized_access^ = $fst$file_access_options []) THEN
          IF (NOT file_is_expired) AND expiration_reduced_access THEN
            osp$set_status_condition (ame$ansi_file_unexpired, status);
            osp$append_status_file (osc$status_parameter_delimiter, file.path (1, file.file_path_size),
                  status);
            osp$append_status_parameter (osc$status_parameter_delimiter, volume_descriptor.external_vsn,
                  status);
            osp$append_status_parameter (osc$status_parameter_delimiter, volume_descriptor.recorded_vsn,
                  status);
          ELSE
            osp$set_status_condition (ame$insufficient_file_access, status);
            osp$append_status_file (osc$status_parameter_delimiter, file.path (1, file.file_path_size),
                  status);
          IFEND;
        IFEND;
      IFEND;
    ELSE
      request.authorized_access^ := request.proposed_access;
    IFEND;

    IF cause_for_dismount (status) THEN
      dismount_current_volume (file_identifier, layer_number, ignore_status);
    IFEND;

  PROCEND authorize_file_access;
?? OLDTITLE ??
?? NEWTITLE := '    authorize_file_reuse ', EJECT ??

  PROCEDURE authorize_file_reuse
    (    file: fst$file_reference;
         file_identifier: amt$file_identifier;
         request: fst$ts_authorize_file_reuse;
         layer_number: amt$fap_layer_number;
         volume_descriptor: rmt$volume_descriptor;
     VAR status: ost$status);

{
{    This procedure ensures that each ANSI file is written with the same file
{ accessibility as the first file of a labeled file set.  Further, this procedure
{ ensures that the existing ANSI file is expired before it can be rewritten.
{
{    A REMOVABLE_MEDIA_ADMINISTRATOR (RMA) is not given any special consideration
{ when rewriting labels on the volume set.
{
{    REQUEST parameters:
{
{       enforce_tape_security (input):  Indicates whether or not tape security
{             is to be enforced.  The FILE_ACCESSIBILITY policy is subject to the
{             value of this parameter; the expiration policy is not.
{
{       initial_volume_classification (input):  This is the classification of the
{             initial volume of the volume set.
{
{       initial_volume_header_labels (input):  Header label sequence read from
{             the first volume of the file set.  These labels determine the
{             extent to which the security parameters (file_accessibiliy,
{             owner_identifier, and volume_accessibility) may be changed as new
{             labels are written.
{
{       original_header_labels (input):  These are the header labels that are
{             being replaced by the proposed_header_labels.
{
{       proposed_header_labels (input):  These are the header labels that are
{             to be written.
{
?? EJECT ??

    VAR
      existing_fa: string (1),
      file_is_expired: boolean,
      hdr1_label: ^fst$ansi_hdr1_label,
      ignore_hdr2_label: ^fst$ansi_hdr2_label,
      ignore_status: ost$status,
      ignore_vol1_label: ^fst$ansi_vol1_label,
      requested_fa: string (1);

    status.normal := TRUE;

    locate_labels (request.original_header_labels, ignore_vol1_label, hdr1_label, ignore_hdr2_label);
    IF (hdr1_label <> NIL) THEN
      fsp$analyze_file_expiration (hdr1_label^.expiration_date, file_is_expired, status);
    ELSE
      file_is_expired := TRUE;
    IFEND;

    IF status.normal AND file_is_expired THEN
      IF request.enforce_tape_security THEN
        locate_labels (request.proposed_header_labels, ignore_vol1_label, hdr1_label, ignore_hdr2_label);
        IF (hdr1_label <> NIL) THEN
          existing_fa := request.initial_volume_classification.labeled.file_accessibility;
          requested_fa := hdr1_label^.accessibility;
          IF NOT file_accessibility_matches (existing_fa, requested_fa) THEN
            osp$set_status_condition (ame$improper_security_change, status);
          IFEND;
        ELSE
          osp$set_status_condition (ame$label_not_in_sequence, status);
          osp$append_status_parameter (osc$status_parameter_delimiter, ' ', status);
          osp$append_status_parameter (osc$status_parameter_delimiter, 'HDR1', status);
        IFEND;
      IFEND;
    ELSE
      osp$set_status_condition (ame$ansi_file_unexpired, status);
    IFEND;
    IF (NOT status.normal) THEN
      CASE status.condition OF
      = ame$ansi_file_unexpired, ame$improper_security_change =
        osp$append_status_file (osc$status_parameter_delimiter, file, status);
        osp$append_status_parameter (osc$status_parameter_delimiter, volume_descriptor.external_vsn, status);
        osp$append_status_parameter (osc$status_parameter_delimiter, volume_descriptor.recorded_vsn, status);
      ELSE
      CASEND;

      IF cause_for_dismount (status) THEN
        dismount_current_volume (file_identifier, layer_number, ignore_status);
      IFEND;
    IFEND;

  PROCEND authorize_file_reuse;
?? OLDTITLE ??
?? NEWTITLE := '    authorize_file_set_mount ', EJECT ??

  PROCEDURE authorize_file_set_mount
    (    file: fst$resolved_file_reference;
         file_identifier: amt$file_identifier;
         request: fst$ts_authorize_file_set_mount;
         layer_number: amt$fap_layer_number;
         volume_descriptor: rmt$volume_descriptor;
     VAR status: ost$status);

{
{    This procedure ensures that the user has sufficient privilege to access
{ the first volume of a file set.  If access is granted, the authorized modes
{ of access are returned.  Subsequent access to existing files in the file set
{ is limited by this validation.
{
{    REQUEST parameters:
{
{       access_method (input):  Identifies how the user intends to access the
{             file set.  A user who is executing within the
{             SYSTEM_OPERATOR_UTILITY with the REMOVABLE_MEDIA_ADMINISTRATION
{             capability active is called an RMA.  An RMA may access any volume
{             as UNLABELED or as NON_STANDARD_LABELED.  An RMA may access any
{             undamaged, labeled volume using any access method ( LABELED,
{             NON_STANDARD_LABELED, or UNLABELED).  A damaged, labeled volume
{             may only be requested by an RMA accessed as either UNLABELED or
{             NON_STANDARD_LABELED.  A non-RMA may not request a labeled volume
{             using either NON_STANDARD_LABELED or UNLABELED.  Unlabeled access
{             allows the reading and writing of labels as data.
{             Non-standard-labeled access allows the reading and writing of
{             labels as data and allows reading beyond the logical end of a
{             volume.
{
{       enforce_tape_security (input):  Indicates whether or not tape security
{             is to be enforced.
{
{       header_labels (input):  Header label sequence read from the volume.
{             This is NIL for an unlabeled volume or a volume with a read error
{             at loadpoint.  This parameter is not used but is provided as a
{             convenience for the site that may implement enhanced security
{             policies based upon volume header labels not normally analyzed by
{             NOS/VE.
{
{       proposed_access (input):  Identifies the modes of access currently
{             requested and currently granted to this instance of open of the
{             tape file.
{
{       proposed_access_defaulted (input):  Indicates whether or not the modes
{             of access were explicitly requested by the user.
{
{       volume_classification (input):  The classification of the first volume
{             of the volume set.  This classification was made by first calling
{             rmp$classify_tape_volume.  If the volume is classified as blank,
{             another read is performed to determine if there is any data in
{             the first ansi file on the volume.  If there is no data found,
{             the blank classification is retained.  Note that if the volume is
{             classified as labeled and damaged due to excessive tape labels,
{             the volume is not currently positioned after a tapemark.
{
{       authorized_access (output):  Returns the modes of access that are
{             authorized to the user for this instance of open.  If the
{             proposed_access_defaulted, the access returned may be a subset of
{             the originally proposed_access.
{
{       file_set_access (output):  Returns the modes of access that are
{             authorized to the user for the file set.
{
?? EJECT ??

    VAR
      authorized_access: fst$file_access_options,
      epix_tape: boolean,
      expired: boolean,
      family: ost$family_name,
      ignore_status: ost$status,
      removable_media_group: ost$name,
      requested_fa: string (1),
      requested_group: string (13),
      requested_oi: string (14),
      requested_va: string (1),
      required_owner_identifier: string (14),
      returned_attributes: fst$tla_returned_attributes,
      user: ost$user_name,
      vc: rmt$tape_volume_classification;

?? NEWTITLE := '      validate_labeled_external', EJECT ??

    PROCEDURE validate_labeled_external;

      IF status.normal AND (vc.labeled.file_accessibility <> ' ') THEN
        IF fsc$tape_file_accessibility IN returned_attributes THEN
          IF vc.labeled.file_accessibility <> requested_fa THEN
            osp$set_status_condition (ame$unknown_volume, status);
          IFEND;
        ELSE
          osp$set_status_condition (ame$unknown_volume, status);
        IFEND;
      IFEND;

      IF status.normal AND (vc.labeled.external_owner_identifier <> ' ') THEN
        IF fsc$tape_owner_identification IN returned_attributes THEN
          IF vc.labeled.external_owner_identifier <> requested_oi THEN
            osp$set_status_condition (ame$unknown_volume, status);
          IFEND;
        ELSE
          osp$set_status_condition (ame$unknown_volume, status);
        IFEND;
      IFEND;

      IF status.normal AND (vc.labeled.volume_accessibility <> ' ') THEN
        IF fsc$tape_volume_accessibility IN returned_attributes THEN
          IF vc.labeled.volume_accessibility <> requested_va THEN
            osp$set_status_condition (ame$unknown_volume, status);
          IFEND;
        ELSE
          osp$set_status_condition (ame$unknown_volume, status);
        IFEND;
      IFEND;
    PROCEND validate_labeled_external;
?? OLDTITLE ??
?? NEWTITLE := '      validate_labeled_for_group', EJECT ??

    PROCEDURE validate_labeled_for_group;

      IF status.normal AND (vc.labeled.file_accessibility <> ' ') THEN
        IF fsc$tape_file_accessibility IN returned_attributes THEN
          IF vc.labeled.file_accessibility <> requested_fa THEN
            osp$set_status_condition (ame$unknown_volume, status);
          IFEND;
        ELSE
          osp$set_status_condition (ame$unknown_volume, status);
        IFEND;
      IFEND;

      IF status.normal AND (fsc$tape_owner_identification IN returned_attributes) THEN
        osp$set_status_condition (ame$unknown_volume, status);
      ELSEIF fsc$tape_removable_media_group IN returned_attributes THEN
        IF vc.labeled.removable_media_group <> requested_group THEN
          osp$set_status_condition (ame$unknown_volume, status);
        IFEND;
      IFEND;

      IF status.normal AND (fsc$tape_volume_accessibility IN returned_attributes) THEN
        IF vc.labeled.volume_accessibility <> requested_va THEN
          osp$set_status_condition (ame$unknown_volume, status);
        IFEND;
      IFEND;
    PROCEND validate_labeled_for_group;
?? OLDTITLE ??
?? NEWTITLE := '      validate_labeled_for_user', EJECT ??

    PROCEDURE validate_labeled_for_user;

      IF vc.labeled.user = user (1, 14) THEN
        IF status.normal AND (vc.labeled.file_accessibility <> ' ') THEN
          IF fsc$tape_file_accessibility IN returned_attributes THEN
            IF vc.labeled.file_accessibility <> requested_fa THEN
              osp$set_status_condition (ame$unknown_volume, status);
            IFEND;
          ELSE
            osp$set_status_condition (ame$unknown_volume, status);
          IFEND;
        IFEND;

        IF status.normal THEN
          IF fsc$tape_owner_identification IN returned_attributes THEN
            IF vc.labeled.user <> requested_oi THEN
              osp$set_status_condition (ame$unknown_volume, status);
            IFEND;
          ELSEIF fsc$tape_removable_media_group IN returned_attributes THEN
            osp$set_status_condition (ame$unknown_volume, status);
          IFEND;
        IFEND;

        IF status.normal AND (fsc$tape_volume_accessibility IN returned_attributes) THEN
          IF vc.labeled.volume_accessibility <> requested_va THEN
            osp$set_status_condition (ame$unknown_volume, status);
          IFEND;
        IFEND;
      ELSE
        osp$set_status_condition (ame$unknown_volume, status);
      IFEND;
    PROCEND validate_labeled_for_user;
?? OLDTITLE ??
?? NEWTITLE := '      validate_ve_password_protected', EJECT ??

    PROCEDURE validate_ve_password_protected;

      IF vc.labeled.file_accessibility <> ' ' THEN
        IF fsc$tape_file_accessibility IN returned_attributes THEN
          IF vc.labeled.file_accessibility <> requested_fa THEN
            osp$set_status_condition (ame$unknown_volume, status);
          IFEND;
        ELSE
          osp$set_status_condition (ame$unknown_volume, status);
        IFEND;
      IFEND;

      IF status.normal AND (vc.labeled.ve_owner_identifier <> ' ') THEN
        IF fsc$tape_owner_identification IN returned_attributes THEN
          IF vc.labeled.ve_owner_identifier <> requested_oi THEN
            osp$set_status_condition (ame$unknown_volume, status);
          IFEND;
        ELSE
          osp$set_status_condition (ame$unknown_volume, status);
        IFEND;
      IFEND;

      IF status.normal AND (vc.labeled.volume_accessibility <> ' ') THEN
        IF fsc$tape_volume_accessibility IN returned_attributes THEN
          IF vc.labeled.volume_accessibility <> requested_va THEN
            osp$set_status_condition (ame$unknown_volume, status);
          IFEND;
        ELSE
          osp$set_status_condition (ame$unknown_volume, status);
        IFEND;
      IFEND;
    PROCEND validate_ve_password_protected;
?? OLDTITLE, EJECT ??
    status.normal := TRUE;

    expired := TRUE;
    request.file_set_access^ := -$fst$file_access_options [];
    IF request.enforce_tape_security THEN
      vc := request.volume_classification;
      IF avp$removable_media_admin () THEN
        IF request.access_method = amc$labeled THEN
          IF (vc.volume_label_type = rmc$indeterminate_volume_type) OR
                ((vc.volume_label_type = rmc$labeled_volume_type) AND
                (vc.labeled.volume_security_type = rmc$vst_access_restricted) AND (NOT vc.labeled.blank)) THEN
            osp$set_status_condition (ame$volume_access_restricted, status);
          ELSE
            request.authorized_access^ := request.proposed_access;
          IFEND;
        ELSE
          request.authorized_access^ := request.proposed_access;
        IFEND;
      ELSE
        get_user_identification (file, family, user, status);
        IF status.normal THEN
          authorized_access := request.proposed_access;
          CASE vc.volume_label_type OF
          = rmc$labeled_volume_type =
            IF request.access_method = amc$labeled THEN
              get_explicit_attributes (file, requested_fa, requested_group, requested_oi, requested_va,
                    returned_attributes, status);
              IF status.normal THEN
                CASE vc.labeled.volume_security_type OF
                = rmc$vst_access_restricted =
                  IF NOT vc.labeled.blank THEN
                    osp$set_status_condition (ame$volume_access_restricted, status);
                  IFEND;
                = rmc$vst_labeled_external =
                  IF NOT vc.labeled.blank THEN {ANSI blank labeling convention looks like this case}
                    avp$get_removable_media_access (user, family, rmc$labeled_external_tapes,
                          request.file_set_access^, status);
                  IFEND;
                  enforce_epix_security (vc.labeled.file_accessibility, vc.labeled.implementation_identifier,
                       {user_is_owner} (user (1, 14) = vc.labeled.external_owner_identifier),
                       vc.labeled.volume_accessibility, authorized_access, epix_tape,
                       request.file_set_access^);
                  IF NOT epix_tape THEN
                    validate_labeled_external;
                  IFEND;
                = rmc$vst_ve_labeled_for_group =
                  removable_media_group := vc.labeled.removable_media_group;
                  avp$get_removable_media_access (user, family, removable_media_group,
                        request.file_set_access^, status);
                  validate_labeled_for_group;
                = rmc$vst_ve_labeled_for_user =
                  validate_labeled_for_user;
                = rmc$vst_ve_password_protected =
                  validate_ve_password_protected;
                ELSE
                CASEND;
              IFEND;
            ELSE {labeled but requested with unlabeled or non standard labeled access}
              osp$set_status_condition (ame$unknown_volume, status);
            IFEND;
            IF NOT vc.labeled.expired THEN
              request.file_set_access^ := request.file_set_access^ *
                    (-$fst$file_access_options [fsc$modify, fsc$shorten]);
              expired := FALSE;
            IFEND;
          = rmc$indeterminate_volume_type =
            osp$set_status_condition (ame$volume_access_restricted, status);
          = rmc$unlabeled_volume_type =
            IF request.access_method = amc$unlabeled THEN
              avp$get_removable_media_access (user, family, rmc$unlabeled_tapes, request.file_set_access^,
                    status);
            ELSE
              osp$set_status_condition (ame$unknown_volume, status);
            IFEND;
          ELSE
          CASEND;
          authorized_access := request.file_set_access^ * authorized_access;
          request.authorized_access^ := $fst$file_access_options [];
          IF status.normal THEN
            IF request.proposed_access_defaulted THEN
              request.authorized_access^ := authorized_access;
            ELSE
              IF authorized_access = request.proposed_access THEN
                request.authorized_access^ := request.proposed_access;
              IFEND;
            IFEND;
            IF request.authorized_access^ = $fst$file_access_options [] THEN
              IF (NOT expired) AND (fsc$shorten IN request.proposed_access) THEN
                osp$set_status_condition (ame$ansi_file_unexpired, status);
              ELSE
                osp$set_status_condition (ame$unknown_volume, status);
              IFEND;
            IFEND;
          IFEND;
        IFEND;
      IFEND;
    ELSE
      request.authorized_access^ := request.proposed_access;
    IFEND;
    IF (NOT status.normal) THEN
      CASE status.condition OF
      = ame$ansi_file_unexpired =
        osp$append_status_file (osc$status_parameter_delimiter, file.path (1, file.file_path_size), status);
        osp$append_status_parameter (osc$status_parameter_delimiter, volume_descriptor.external_vsn, status);
        osp$append_status_parameter (osc$status_parameter_delimiter, volume_descriptor.recorded_vsn, status);
      = ame$unknown_volume =
        osp$append_status_parameter (osc$status_parameter_delimiter, volume_descriptor.external_vsn, status);
        osp$append_status_parameter (osc$status_parameter_delimiter, volume_descriptor.recorded_vsn, status);
      = ame$volume_access_restricted =
        osp$append_status_file (osc$status_parameter_delimiter, file.path (1, file.file_path_size), status);
        osp$append_status_parameter (osc$status_parameter_delimiter, volume_descriptor.external_vsn, status);
      ELSE
      CASEND;
      IF cause_for_dismount (status) THEN
        dismount_current_volume (file_identifier, layer_number, ignore_status);
      IFEND;
    IFEND;

  PROCEND authorize_file_set_mount;
?? OLDTITLE ??
?? NEWTITLE := '    authorize_file_set_reuse ', EJECT ??
  PROCEDURE authorize_file_set_reuse
    (    file: fst$resolved_file_reference;
         file_identifier: amt$file_identifier;
         request: fst$ts_authorize_file_set_reuse;
         layer_number: amt$fap_layer_number;
         volume_descriptor: rmt$volume_descriptor;
     VAR status: ost$status);

{
{    This procedure ensures that the user has sufficient privilege to rewrite
{ the first volume of a labeled file set.  The user must at a minimum have
{ WRITE access to the file set.  If access is granted, the authorized modes of
{ access are returned.  Subsequent access to existing files in the file set is
{ limited to the file_set_access.  If authorization is given to rewrite the
{ labels at the beginning of the file set, the PROPOSED_HEADER_LABELS are
{ written via a subsequent WRITE_TAPE_LABELS FAP request.
{
{    Even though tape security may not be enabled, this procedure ensures that
{ the user cannot specify an Owner Identifier value other than the login-user
{ for a temporary file and the master catalog name of a permanent file when
{ labeling a volume for the user.  When labeling for a group, this procedure
{ ensures that the user belongs to the group.  This is done to ensure that the
{ writer will be able to access the tape after it is written and tape security
{ is subsequently enabled.  Note that this policy only affects volumes whose
{ Implementation Identifier is 'NOS/VE V2.0' and whose Volume Accessibility is A.
{
{    If a user specifies a value for a security field and the value is not
{ included in the labels that are written, this procedure writes a warning
{ message to the $ERRORS file and to the job log.  This can happen in several
{ ways:
{
{  1.  The user is attempting to label a volume for a REMOVABLE_MEDIA_GROUP but
{      the file set contains CDC_VERSION_ONE labels which preclude this.
{
{  2.  The user is attempting to enhance the security of a volume by specifying
{      an OWNER_IDENTIFIER but the file set contains CDC_VERSION_TWO labels,
{      VA=A, and the value specified is not the name of the login_user.
{
{  3.  After successfully mounting the initial volume of the file set, the user
{      specified security fields (via CHANGE_TAPE_LABEL_ATTRIBUTES or
{      FSP$OPEN_FILE) that do not match the existing security fields that are
{      <> SPACE.  An existing field that is <> SPACE cannot be changed without
{      first initializing the volume.
{
{      A REMOVABLE_MEDIA_ADMINISTRATOR (RMA) is not given any special
{      consideration when rewriting labels on the volume set.  The RMA must be
{      a member of any group referenced in the VOL1 OWNER_IDENTIFIER.  The RMA
{      is not allowed to label a volume for another user.
{
{      REQUEST parameters:
{
{       enforce_tape_security (input):  Indicates whether or not tape security
{             is to be enforced.  The expiration policy is independent of the
{             value of this parameter.
{
{       initial_volume_classification (input):  This is the classification of
{             the initial volume of the volume set.  The classification
{             determines the extent to which the security parameters
{             (file_accessibiliy, owner_identifier, and volume_accessibility)
{             may be changed as new labels are written at the beginning of the
{             file set.
{
{       initial_volume_header_labels (input):  Header label sequence read from
{             the first volume of the file set.  This paramter is not used but
{             is provided for a site that may extend the security policy based
{             on volume header labels not normally analyzed by NOS/VE.
{
{       proposed_access (input):  Identifies the modes of access requested and
{             currently granted to this instance of open of the tape file.
{
{       proposed_access_defaulted (input):  Indicates whether or not the modes
{             of access were explicitly specified by the user.
{
{       proposed_header_labels (input):  These are the header labels that are
{             to be written to the beginning of the file set.
{
{       proposed_volume_classification (input):  This is the classification of
{             the volume labels that are to be written at the beginning of the
{             file set.
{
{       authorized_access (output):  Returns the modes of access that are
{             authorized to the user for this instance of open.  If the
{             proposed_access_defaulted, the access returned may be a subset of
{             the originally proposed_access.  The authorized access is
{             initially constrained by the file_set_access and then by the
{             proposed_access.  To reuse the file set, SHORTEN access is
{             required or abnormal status is returned.
{
{       file_set_access (output):  Returns the modes of access that are
{             authorized to the user for the file set.  If the volume is to
{             become labeled for a REMOVABLE_MEDIA_GROUP, the user must be
{             authorized for WRITE access within the group; this supercedes any
{             access the user may have originally been authorized when the file
{             set was mounted.  If the existing file set is classified as
{             labeled external, the file_set_access is determined by the
{             LABELED_EXTERNAL_TAPES validation.

?? EJECT ??

    VAR
      authorized_access: fst$file_access_options,
      existing_fa: string (1),
      existing_va: string (1),
      family: ost$family_name,
      ignore_status: ost$status,
      proposed_fa: string (1),
      proposed_group: ost$name,
      proposed_va: string (1),
      returned_attributes: fst$tla_returned_attributes,
      specified_fa: string (1),
      specified_group: string (13),
      specified_oi: string (14),
      specified_va: string (1),
      user: ost$user_name;

?? NEWTITLE := '      emit_warning_messages', EJECT ??

    PROCEDURE emit_warning_messages;

      VAR
        ignore_status: ost$status,
        logset: pmt$ascii_logset,
        message_status: ost$status;

      logset := $pmt$ascii_logset [pmc$job_log];
      IF fsc$tape_file_accessibility IN returned_attributes THEN
        IF specified_fa <> proposed_fa THEN
          osp$set_status_condition (ame$ignored_file_accessibility, message_status);
          osp$append_status_file (osc$status_parameter_delimiter, file.path (1, file.file_path_size),
                message_status);
          osp$generate_error_message (message_status, ignore_status);
          osp$generate_log_message (logset, message_status, ignore_status);
        IFEND;
      IFEND;

      IF fsc$tape_owner_identification IN returned_attributes THEN
        CASE request.proposed_volume_classification.labeled.volume_security_type OF
        = rmc$vst_ve_labeled_for_group =
          osp$set_status_condition (ame$ignored_owner_identifier, message_status);
          osp$append_status_file (osc$status_parameter_delimiter, file.path (1, file.file_path_size),
                message_status);
          osp$generate_error_message (message_status, ignore_status);
          osp$generate_log_message (logset, message_status, ignore_status);
        = rmc$vst_ve_labeled_for_user =
          IF specified_oi <> user (1, 14) THEN
            osp$set_status_condition (ame$ignored_owner_identifier, message_status);
            osp$append_status_file (osc$status_parameter_delimiter, file.path (1, file.file_path_size),
                  message_status);
          IFEND;
        = rmc$vst_ve_password_protected =
          IF specified_oi <> request.proposed_volume_classification.labeled.ve_owner_identifier THEN
            osp$set_status_condition (ame$ignored_owner_identifier, message_status);
            osp$append_status_file (osc$status_parameter_delimiter, file.path (1, file.file_path_size),
                  message_status);
            osp$generate_error_message (message_status, ignore_status);
            osp$generate_log_message (logset, message_status, ignore_status);
          IFEND;
        ELSE
        CASEND;
      IFEND;

      IF fsc$tape_removable_media_group IN returned_attributes THEN
        CASE request.proposed_volume_classification.labeled.volume_security_type OF
        = rmc$vst_ve_labeled_for_group =
          IF specified_group <> proposed_group THEN
            osp$set_status_condition (ame$ignored_rmg, message_status);
            osp$append_status_file (osc$status_parameter_delimiter, file.path (1, file.file_path_size),
                  message_status);
            osp$generate_error_message (message_status, ignore_status);
            osp$generate_log_message (logset, message_status, ignore_status);
          IFEND;
        = rmc$vst_ve_labeled_for_user, rmc$vst_ve_password_protected =
          osp$set_status_condition (ame$ignored_rmg, message_status);
          osp$append_status_file (osc$status_parameter_delimiter, file.path (1, file.file_path_size),
                message_status);
          osp$generate_error_message (message_status, ignore_status);
          osp$generate_log_message (logset, message_status, ignore_status);
        ELSE
        CASEND;
      IFEND;

      IF fsc$tape_volume_accessibility IN returned_attributes THEN
        IF specified_va <> proposed_va THEN
          osp$set_status_condition (ame$ignored_vol_accessibility, message_status);
          osp$append_status_file (osc$status_parameter_delimiter, file.path (1, file.file_path_size),
                message_status);
          osp$generate_error_message (message_status, ignore_status);
          osp$generate_log_message (logset, message_status, ignore_status);
        IFEND;
      IFEND;

    PROCEND emit_warning_messages;
?? OLDTITLE ??
?? NEWTITLE := '      validate_labeled_for_group', EJECT ??

    PROCEDURE validate_labeled_for_group;

      IF NOT request.initial_volume_classification.labeled.blank THEN
        CASE request.initial_volume_classification.labeled.volume_security_type OF
        = rmc$vst_labeled_external =
          osp$set_status_condition (ame$improper_security_change, status);
        = rmc$vst_ve_labeled_for_group =
          IF NOT owner_identifier_matches (request.initial_volume_classification.labeled.
                removable_media_group, request.proposed_volume_classification.labeled.removable_media_group)
                THEN
            osp$set_status_condition (ame$improper_security_change, status);
          IFEND;
        = rmc$vst_ve_labeled_for_user =
          osp$set_status_condition (ame$improper_security_change, status);
        = rmc$vst_ve_password_protected =
          IF request.initial_volume_classification.labeled.ve_owner_identifier <> ' ' THEN
            osp$set_status_condition (ame$improper_security_change, status);
          ELSEIF request.initial_volume_classification.labeled.implementation_identifier <>
                request.proposed_volume_classification.labeled.implementation_identifier THEN
            osp$set_status_condition (ame$improper_security_change, status);
          IFEND;
        ELSE
        CASEND;
      IFEND;
    PROCEND validate_labeled_for_group;
?? OLDTITLE ??
?? NEWTITLE := '      validate_labeled_for_user', EJECT ??

    PROCEDURE validate_labeled_for_user;

      authorized_access := request.proposed_access;
      IF request.proposed_volume_classification.labeled.user = user (1, 14) THEN
        IF NOT request.initial_volume_classification.labeled.blank THEN
          CASE request.initial_volume_classification.labeled.volume_security_type OF
          = rmc$vst_labeled_external =
            osp$set_status_condition (ame$improper_security_change, status);
          = rmc$vst_ve_labeled_for_group =
            osp$set_status_condition (ame$improper_security_change, status);
          = rmc$vst_ve_labeled_for_user =
            IF NOT owner_identifier_matches (request.initial_volume_classification.labeled.user,
                  request.proposed_volume_classification.labeled.user) THEN
              osp$set_status_condition (ame$improper_security_change, status);
            IFEND;
          = rmc$vst_ve_password_protected =
            IF request.initial_volume_classification.labeled.ve_owner_identifier <> ' ' THEN
              osp$set_status_condition (ame$improper_security_change, status);
            ELSEIF request.initial_volume_classification.labeled.implementation_identifier <>
                  request.proposed_volume_classification.labeled.implementation_identifier THEN
              osp$set_status_condition (ame$improper_security_change, status);
            IFEND;
          ELSE
          CASEND;
        IFEND;
      ELSE
        osp$set_status_condition (ame$improper_security_change, status);
      IFEND;
    PROCEND validate_labeled_for_user;
?? OLDTITLE ??
?? NEWTITLE := '      validate_ve_password_protected', EJECT ??

    PROCEDURE validate_ve_password_protected;

      authorized_access := request.proposed_access;
      IF NOT request.initial_volume_classification.labeled.blank THEN
        CASE request.initial_volume_classification.labeled.volume_security_type OF
        = rmc$vst_labeled_external =
          osp$set_status_condition (ame$improper_security_change, status);
        = rmc$vst_ve_password_protected =
          IF NOT owner_identifier_matches (request.initial_volume_classification.labeled.ve_owner_identifier,
                request.proposed_volume_classification.labeled.ve_owner_identifier) THEN
            osp$set_status_condition (ame$improper_security_change, status);
          IFEND;
        = rmc$vst_ve_labeled_for_group, rmc$vst_ve_labeled_for_user =
          osp$set_status_condition (ame$improper_security_change, status);
        ELSE
        CASEND;
      IFEND;
    PROCEND validate_ve_password_protected;
?? OLDTITLE, EJECT ??

    status.normal := TRUE;

    request.authorized_access^ := $fst$file_access_options [];
    IF request.initial_volume_classification.labeled.expired THEN
      request.file_set_access^ := -$fst$file_access_options [];
      get_user_identification (file, family, user, status);
      IF status.normal THEN
        existing_fa := request.initial_volume_classification.labeled.file_accessibility;
        existing_va := request.initial_volume_classification.labeled.volume_accessibility;
        proposed_fa := request.proposed_volume_classification.labeled.file_accessibility;
        proposed_va := request.proposed_volume_classification.labeled.volume_accessibility;
        IF request.enforce_tape_security THEN

          CASE request.proposed_volume_classification.labeled.volume_security_type OF
          = rmc$vst_labeled_external =
            {NOS/VE only writes NOS/VE implementation labels
            osp$set_status_condition (ame$improper_security_change, status);
          ELSE
            IF file_accessibility_matches (existing_fa, proposed_fa) AND
                  volume_accessibility_matches (existing_va, proposed_va) THEN
              get_explicit_attributes (file, specified_fa, specified_group, specified_oi, specified_va,
                    returned_attributes, status);
            ELSE
              osp$set_status_condition (ame$improper_security_change, status);
            IFEND;
          CASEND;

          IF status.normal THEN
            CASE request.proposed_volume_classification.labeled.volume_security_type OF
            = rmc$vst_ve_labeled_for_group =
              proposed_group := request.proposed_volume_classification.labeled.removable_media_group;
              avp$get_removable_media_access (user, family, proposed_group, request.file_set_access^, status);
              IF status.normal THEN
                validate_labeled_for_group;
              IFEND;
            = rmc$vst_ve_labeled_for_user =
              validate_labeled_for_user;
            = rmc$vst_ve_password_protected =
              validate_ve_password_protected;
            ELSE
              osp$set_status_condition (ame$improper_security_change, status);
            CASEND;
          IFEND;

          IF status.normal THEN
            emit_warning_messages;
          IFEND;
        ELSE {tape security unenforced}
          CASE request.proposed_volume_classification.labeled.volume_security_type OF
          = rmc$vst_ve_labeled_for_group =
            IF request.initial_volume_classification.volume_label_type = rmc$labeled_volume_type THEN
              CASE request.initial_volume_classification.labeled.volume_security_type OF
                = rmc$vst_ve_labeled_for_group =
                IF request.proposed_volume_classification.labeled.removable_media_group <> request.
                       initial_volume_classification.labeled.removable_media_group THEN
                  request.file_set_access^ := -$fst$file_access_options [fsc$modify, fsc$shorten];
                IFEND;
              ELSE
                IF request.proposed_volume_classification.labeled.user <> user (1,14) THEN
                  proposed_group := request.proposed_volume_classification.labeled.removable_media_group;
                  avp$get_removable_media_access (user, family, proposed_group, request.file_set_access^,
                         status);
                IFEND;
              CASEND;
            IFEND;
          = rmc$vst_ve_labeled_for_user =
            IF request.initial_volume_classification.volume_label_type = rmc$labeled_volume_type THEN
              CASE request.initial_volume_classification.labeled.volume_security_type OF
                = rmc$vst_ve_labeled_for_user =
                IF request.proposed_volume_classification.labeled.user <> request.
                       initial_volume_classification.labeled.user THEN
                  request.file_set_access^ := -$fst$file_access_options [fsc$modify, fsc$shorten];
                IFEND;
              ELSE
                IF request.proposed_volume_classification.labeled.user <> user (1,14) THEN
                  request.file_set_access^ := -$fst$file_access_options [fsc$modify, fsc$shorten];
                IFEND;
              CASEND;
            IFEND;
          ELSE
          CASEND;
        IFEND; {End of tape security enforcement}

        authorized_access := request.file_set_access^ * request.proposed_access;
        IF status.normal THEN
          IF request.proposed_access_defaulted THEN
            request.authorized_access^ := authorized_access;
          ELSE
            IF authorized_access = request.proposed_access THEN
              request.authorized_access^ := request.proposed_access;
            IFEND;
          IFEND;
          IF request.initial_volume_classification.labeled.blank THEN
            IF NOT ((fsc$append IN request.authorized_access^) OR (fsc$shorten IN request.
                  authorized_access^)) THEN
            osp$set_status_condition (ame$insufficient_volume_access, status);
            IFEND;
          ELSEIF NOT (fsc$shorten IN request.authorized_access^) THEN
            osp$set_status_condition (ame$insufficient_volume_access, status);
          IFEND;
        IFEND;
      IFEND; {End of status check on get_user_identification}
    ELSE {file unexpired}
      request.file_set_access^ := -$fst$file_access_options [fsc$modify, fsc$shorten];
      osp$set_status_condition (ame$ansi_file_unexpired, status);
    IFEND;
    IF NOT status.normal THEN
      CASE status.condition OF
      = ame$ansi_file_unexpired, ame$improper_security_change, ame$insufficient_volume_access =
        osp$append_status_file (osc$status_parameter_delimiter, file.path (1, file.file_path_size), status);
        osp$append_status_parameter (osc$status_parameter_delimiter, volume_descriptor.external_vsn, status);
        osp$append_status_parameter (osc$status_parameter_delimiter, volume_descriptor.recorded_vsn, status);
      ELSE
      CASEND;
      IF cause_for_dismount (status) THEN
        dismount_current_volume (file_identifier, layer_number, ignore_status);
      IFEND;
    IFEND;

  PROCEND authorize_file_set_reuse;
?? OLDTITLE ??
?? NEWTITLE := '    authorize_section_read ', EJECT ??
  PROCEDURE authorize_section_read
    (    file: fst$resolved_file_reference;
         file_identifier: amt$file_identifier;
         request: fst$ts_authorize_section_read;
         layer_number: amt$fap_layer_number;
         volume_descriptor: rmt$volume_descriptor;
     VAR status: ost$status);

{
{    This procedure is called when reading extends to another volume in the
{ volume set.  The following policies are enforced:
{
{ 1.  A damaged volume can only be accessed by an RMA.
{
{ 2.  The policies for a volume set labeled for a user or a group are more
{     stringent than for other types of volume sets.  This is because NOS/VE
{     ensures consistency of FILE_ACCESSIBILITY, OWNER_IDENTIFIER, and
{     VOLUME_ACCESSIBILITY from the first volume to the last in a volume set
{     labeled for a user or for a group.  If these values do not match, then it
{     is a certainty that the volume is not part of the volume set.
{
{ 3.  A labeled, external volume set or a password protected volume set may not
{     exhibit consistency of security fields among volumes in the volume set.
{     To safeguard the ability to read heterogeneous volume sets, only the
{     policies below are enforced.
{
{ 4.  For all volume sets, the following policies are enforced:
{
{     a.  The FILE_SET_IDENTIFIER of each volume must match that of the initial
{         volume.
{
{     b.  The FILE_SECTION_NUMBER and FILE_SEQUENCE_NUMBERS must be the
{         expected values.
{
{    REQUEST parameters:
{
{       enforce_tape_security (input):  Indicates whether or not tape security
{             is to be enforced.
{
{       current_header_labels (input):  Header label sequence read from the
{             beginning of the volume from which we are about to continue
{             reading.
{
{       current_volume_classification (input):  The classification of the
{             volume that has now been mounted.  This classification was made
{             by first calling rmp$classify_tape_volume.  If the volume is
{             classified as blank, another read is performed to determine if
{             there is any data in the first ansi file on the volume.  If a
{             tapemark is encountered, the blank classification is retained.
{
{       file_section_number (input):  This value is the anticipated file
{             section number of the volume from which we will continue reading.
{
{       file_sequence_number (input):  This value is the anticipated file
{             sequence number of the file from which we will continue reading.
{
{       initial_volume_classification (input):  This is the classification of
{             the initial volume of the volume set.  This classification
{             provides the security parameters (file_accessibiliy,
{             owner_identifier, and volume_accessibility) which must match all
{             subsequent volumes of the file set.
{
{       initial_volume_header_labels (input):  Header label sequence for the
{             first file of the file set.  This parameter is ignored but is
{             provided for the site that extends file security based on volume
{             header labels not normally analyzed by NOS/VE.
{
?? EJECT ??

    VAR
      authorized_access: fst$file_access_options,
      current_fa: string (1),
      current_file_section: 1 .. 9999,
      current_file_sequence: 1 .. 9999,
      current_file_set_identifier: string (6),
      current_va: string (1),
      hdr1_label: ^fst$ansi_hdr1_label,
      ignore_hdr2_label: ^fst$ansi_hdr2_label,
      ignore_status: ost$status,
      ignore_vol1_label: ^fst$ansi_vol1_label,
      initial_fa: string (1),
      initial_va: string (1);

    status.normal := TRUE;

    IF request.enforce_tape_security THEN
      current_fa := request.current_volume_classification.labeled.file_accessibility;
      current_va := request.current_volume_classification.labeled.volume_accessibility;
      initial_fa := request.initial_volume_classification.labeled.file_accessibility;
      initial_va := request.initial_volume_classification.labeled.volume_accessibility;
      CASE request.current_volume_classification.labeled.volume_security_type OF
      = rmc$vst_access_restricted =
        IF NOT avp$removable_media_admin () THEN
          osp$set_status_condition (ame$volume_access_restricted, status);
          osp$append_status_file (osc$status_parameter_delimiter, file.path (1, file.file_path_size), status);
          osp$append_status_parameter (osc$status_parameter_delimiter, volume_descriptor.external_vsn,
                status);
        IFEND;
      = rmc$vst_ve_labeled_for_group =
        IF file_accessibility_matches (current_fa, initial_fa) AND
              volume_accessibility_matches (current_va, initial_va) THEN
          IF NOT ((request.initial_volume_classification.labeled.volume_security_type =
                rmc$vst_ve_labeled_for_group) AND (request.current_volume_classification.labeled.
                removable_media_group = request.initial_volume_classification.labeled.removable_media_group))
                THEN
            osp$set_status_condition (ame$volume_security_conflict, status);
          IFEND;
        ELSE
          osp$set_status_condition (ame$volume_security_conflict, status);
        IFEND;
      = rmc$vst_ve_labeled_for_user =
        IF file_accessibility_matches (current_fa, initial_fa) AND
              volume_accessibility_matches (current_va, initial_va) THEN
          IF NOT ((request.initial_volume_classification.labeled.volume_security_type =
                rmc$vst_ve_labeled_for_user) AND (request.current_volume_classification.labeled.user =
                request.initial_volume_classification.labeled.user)) THEN
            osp$set_status_condition (ame$volume_security_conflict, status);
          IFEND;
        ELSE
          osp$set_status_condition (ame$volume_security_conflict, status);
        IFEND;
      = rmc$vst_labeled_external, rmc$vst_ve_password_protected =
      ELSE
      CASEND;
    IFEND;

    IF status.normal THEN
      locate_labels (request.current_header_labels, ignore_vol1_label, hdr1_label, ignore_hdr2_label);
      IF hdr1_label <> NIL THEN
        current_file_set_identifier := hdr1_label^.file_set_identifier;
        convert_number (hdr1_label^.file_section_number, current_file_section, status);
        IF status.normal THEN
          convert_number (hdr1_label^.file_sequence_number, current_file_sequence, status);
          IF status.normal THEN
            get_boolean_variable ('rmv$omit_strict_hdr1_checking', omit_strict_hdr1_checking);
            IF ((current_file_section <> request.file_section_number) OR
                  (current_file_sequence <> request.file_sequence_number)) AND
                  (NOT omit_strict_hdr1_checking) THEN
              osp$set_status_condition (ame$section_out_of_sequence, status);
            ELSE
              locate_labels (request.initial_volume_header_labels, ignore_vol1_label, hdr1_label,
                    ignore_hdr2_label);
              IF hdr1_label <> NIL THEN
                IF (current_file_set_identifier <> hdr1_label^.file_set_identifier) AND
                      (NOT omit_strict_hdr1_checking) THEN
                  osp$set_status_condition (ame$wrong_file_set_identifier, status);
                  osp$append_status_file (osc$status_parameter_delimiter,
                        file.path (1,file.file_path_size), status);
                  osp$append_status_parameter (osc$status_parameter_delimiter,
                        volume_descriptor.external_vsn, status);
                  osp$append_status_parameter (osc$status_parameter_delimiter,
                        volume_descriptor.recorded_vsn, status);
                  osp$append_status_parameter (osc$status_parameter_delimiter,
                        current_file_set_identifier, status);
                  osp$append_status_parameter (osc$status_parameter_delimiter,
                        hdr1_label^.file_set_identifier, status);
                IFEND;
              IFEND;
            IFEND;
          IFEND;
        IFEND;
      ELSE
        osp$set_status_condition (ame$volume_security_conflict, status);
      IFEND;
    IFEND;

    IF NOT status.normal THEN
      CASE status.condition OF
      = ame$volume_security_conflict =
        osp$append_status_file (osc$status_parameter_delimiter, file.path (1, file.file_path_size), status);
        osp$append_status_parameter (osc$status_parameter_delimiter, volume_descriptor.external_vsn, status);
        osp$append_status_parameter (osc$status_parameter_delimiter, volume_descriptor.recorded_vsn, status);
      = ame$section_out_of_sequence =
        osp$append_status_file (osc$status_parameter_delimiter, file.path (1, file.file_path_size), status);
        osp$append_status_parameter (osc$status_parameter_delimiter, volume_descriptor.external_vsn, status);
        osp$append_status_parameter (osc$status_parameter_delimiter, volume_descriptor.recorded_vsn, status);
        osp$append_status_integer (osc$status_parameter_delimiter, request.file_section_number, {radix} 10,
              {include_radix_specifier} FALSE, status);
        osp$append_status_integer (osc$status_parameter_delimiter, request.file_sequence_number, {radix} 10,
              {include_radix_specifier} FALSE, status);
        osp$append_status_integer (osc$status_parameter_delimiter, current_file_section, {radix} 10,
              {include_radix_specifier} FALSE, status);
        osp$append_status_integer (osc$status_parameter_delimiter, current_file_sequence, {radix} 10,
              {include_radix_specifier} FALSE, status);
        osp$append_status_parameter (osc$status_parameter_delimiter, hdr1_label^.file_set_identifier, status);
      ELSE
      CASEND;
      dismount_current_volume (file_identifier, layer_number, ignore_status);
    IFEND;
  PROCEND authorize_section_read;
?? OLDTITLE ??
?? NEWTITLE := '    authorize_section_write ', EJECT ??

  PROCEDURE authorize_section_write
    (    file: fst$file_reference;
         file_identifier: amt$file_identifier;
         request: fst$ts_authorize_section_write;
         layer_number: amt$fap_layer_number;
         volume_descriptor: rmt$volume_descriptor;
     VAR status: ost$status);

{
{    This procedure is called when writing extends to another volume in the
{ volume set.  The current labels on the volume are examined before the writing
{ of new labels is authorized; the following policies are enforced:
{
{ 1.  The security fields of the current header labels must be consistent with
{     respect to the file set that we are now writing.
{
{ 2.  If the current FILE_SECTION_NUMBER and FILE_SEQUENCE_NUMBER are both 1
{     (one) and the first ANSI file is not expired, access is not authorized.
{     This implies that the volume is the first volume of some other unexpired
{     file set.
{
{     REQUEST parameters:
{
{       enforce_tape_security (input):  Indicates whether or not tape security
{             is to be enforced.  Enforcement of the ANSI file's expiration
{             date is independent of the value of this parameter.
{
{       current_header_labels (input):  Header label sequence read from the
{             beginning of the volume on which we are about to write.
{
{       initial_volume_classification (input):  This is the classification of
{             the initial volume of the volume set.  The classification
{             determines the extent to which the security parameters
{             (file_accessibiliy, owner_identifier, and volume_accessibility)
{             may be changed as new labels are written.
{
{       initial_volume_header_labels (input):  Header label sequence for the
{             first file of the file set.  This parameter is not used, but is
{             provided in case the site has security extensions based upon the
{             other volume header labels not normally analyzed by NOS/VE.
{
?? EJECT ??

    VAR
      current_fa: string (1),
      current_va: string (1),
      current_volume_classification: rmt$tape_volume_classification,
      file_is_expired: boolean,
      hdr1_label: ^fst$ansi_hdr1_label,
      ignore_hdr2_label: ^fst$ansi_hdr2_label,
      ignore_read_labels_status: ost$status,
      ignore_status: ost$status,
      ignore_vol1_label: ^fst$ansi_vol1_label,
      initial_fa: string (1),
      initial_va: string (1);

    status.normal := TRUE;

    ignore_read_labels_status.normal := TRUE;
    rmp$classify_tape_volume (ignore_read_labels_status, request.current_header_labels,
          current_volume_classification, status);
    IF request.enforce_tape_security THEN
      IF status.normal THEN
        current_fa := current_volume_classification.labeled.file_accessibility;
        current_va := current_volume_classification.labeled.volume_accessibility;
        initial_fa := request.initial_volume_classification.labeled.file_accessibility;
        initial_va := request.initial_volume_classification.labeled.volume_accessibility;
        IF file_accessibility_matches (current_fa, initial_fa) AND volume_accessibility_matches (current_va,
            initial_va) THEN
          CASE current_volume_classification.labeled.volume_security_type OF
          = rmc$vst_access_restricted =
            IF NOT current_volume_classification.labeled.blank THEN
              osp$set_status_condition (ame$volume_security_conflict, status);
            IFEND;
          = rmc$vst_labeled_external =
            IF NOT current_volume_classification.labeled.blank THEN
              osp$set_status_condition (ame$volume_security_conflict, status);
            IFEND;
          = rmc$vst_ve_labeled_for_group =
            IF NOT ((request.initial_volume_classification.labeled.volume_security_type =
                  rmc$vst_ve_labeled_for_group) AND owner_identifier_matches
                  (current_volume_classification.labeled.removable_media_group,
                  request.initial_volume_classification.labeled.removable_media_group)) THEN
              osp$set_status_condition (ame$volume_security_conflict, status);
            IFEND;
          = rmc$vst_ve_labeled_for_user =
            IF NOT ((request.initial_volume_classification.labeled.volume_security_type =
                  rmc$vst_ve_labeled_for_user) AND owner_identifier_matches
                  (current_volume_classification.labeled.user, request.initial_volume_classification.labeled.
                  user)) THEN
              osp$set_status_condition (ame$volume_security_conflict, status);
            IFEND;
          = rmc$vst_ve_password_protected =
            IF NOT current_volume_classification.labeled.blank THEN
              IF NOT (request.initial_volume_classification.labeled.volume_security_type =
                    rmc$vst_labeled_external) THEN
                IF NOT owner_identifier_matches (current_volume_classification.labeled.ve_owner_identifier,
                      request.initial_volume_classification.labeled.ve_owner_identifier) THEN
                  osp$set_status_condition (ame$volume_security_conflict, status);
                IFEND;
              IFEND;
            IFEND;
          ELSE
          CASEND;
        ELSE
          osp$set_status_condition (ame$volume_security_conflict, status);
        IFEND;
      IFEND;
    IFEND;
    IF status.normal THEN
      IF NOT current_volume_classification.labeled.blank THEN
        locate_labels (request.current_header_labels, ignore_vol1_label, hdr1_label, ignore_hdr2_label);
        IF hdr1_label <> NIL THEN
          IF (hdr1_label^.file_sequence_number = '0001') AND (hdr1_label^.file_section_number = '0001') AND
                (NOT current_volume_classification.labeled.expired) THEN
            osp$set_status_condition (ame$initial_volume_unexpired, status);
          IFEND;
        IFEND;
      IFEND;
    IFEND;
    IF NOT status.normal THEN
      CASE status.condition OF
      = ame$initial_volume_unexpired, ame$volume_security_conflict =
        osp$append_status_file (osc$status_parameter_delimiter, file, status);
        osp$append_status_parameter (osc$status_parameter_delimiter, volume_descriptor.external_vsn, status);
        osp$append_status_parameter (osc$status_parameter_delimiter, volume_descriptor.recorded_vsn, status);
      ELSE
      CASEND;
      dismount_current_volume (file_identifier, layer_number, ignore_status);
    IFEND;

  PROCEND authorize_section_write;
?? OLDTITLE ??
?? NEWTITLE := '    authorize_volume_reuse ', EJECT ??

  PROCEDURE authorize_volume_reuse
    (    file: fst$file_reference;
         file_identifier: amt$file_identifier;
         request: fst$ts_authorize_volume_reuse;
         layer_number: amt$fap_layer_number;
     VAR status: ost$status);

{
{    This procedure authorizes the attempt by an RMO to initialize a volume.
{ If the site authorizes the volume reuse, this procedure then proceeds to
{ write the blank label group to the volume.
{
{    The validation performed below is redundant, if the RMO uses system
{ commands to initialize a volume.  However, if a site writes its own volume
{ intialization program using FSP$OPEN_FILE, this check ensures that the user
{ of the program has sufficient privilege to reuse the volume.
{
{    If the volume is to become unlabeled, three tapemarks are written.
{
{    If the volume is to become labeled, the PROPOSED_BLANK_LABELS sequence
{ will contain some form of ANSI label sequence.  Options externalized by
{ NOS/VE include one of the following:
{
{  1.  VOL1 * * (ANSI option)
{
{  2.  VOL1 HDR1 HDR2 * * EOF1 EOF2 * * * (CDC_VERSION_ONE or CDC_VERSION_TWO)
{
{  3.  An arbitrary list of strings provided by the command user
{
{      Request Parameters:
{
{       current_header_labels (input) :  Header label sequence read from the
{             volume to be initialized.  This is NIL for an unlabeled volume or
{             a volume with a read error at loadpoint.  This parameter is
{             ignored but is provided to allow a site to do more extensive
{             validation of the existing label group prior to reusing the
{             volume.
{
{       enforce_tape_security (input) :  The policy for reusing a volume is
{             independent of whether or not tape security is in effect.
{             However, the boolean is provided to allow the site to augment
{             this policy dependent upon the value of the boolean.
{
{       proposed_file_label_type (input) :  Identifies the intent of the RMO to
{             create a blank labeled (amc$labeled) or unlabeled (amc$unlabeled)
{             volume.  This parameter is ignored but is provided to enable the
{             site to disallow the creation of an unlabeled volume by an RMO,
{             if this is considered desirable.
{
{       proposed_blank_labels (input) :  This field contains the image of the
{             blank label group to be written to the reused volume.
?? EJECT ??

    VAR
      ignore_status: ost$status,
      local_call_block: amt$call_block;

    status.normal := TRUE;
    IF avp$removable_media_operator () THEN
      local_call_block.operation := amc$write_tape_labels;
      local_call_block.write_tape_labels := request.proposed_blank_labels;
      amp$access_method (file_identifier, local_call_block, layer_number, status);
    ELSE
      osp$set_status_condition (ame$rmo_privilege_required, status);
      osp$append_status_file (osc$status_parameter_delimiter, file, status);
      dismount_current_volume (file_identifier, layer_number, ignore_status);
    IFEND;

  PROCEND authorize_volume_reuse;
?? OLDTITLE ??
?? NEWTITLE := '    cause_for_dismount', EJECT ??

  FUNCTION [INLINE] cause_for_dismount
    (    status: ost$status): boolean;

{ This function identifies certain exception conditions as irrelevant.
{ These conditions are considered irrelevant ONLY when they are detected after the
{ file set is successfully mounted and before the target ANSI file is found during
{ a search of the volume set.

    IF status.normal THEN
      cause_for_dismount := FALSE;
    ELSE
      CASE status.condition OF
      = ame$ansi_file_unexpired, ame$insufficient_file_access =
        cause_for_dismount := FALSE;
      ELSE
        cause_for_dismount := TRUE;
      CASEND;
    IFEND;

  FUNCEND cause_for_dismount;

?? OLDTITLE ??
?? NEWTITLE := '    convert_number ', EJECT ??

  PROCEDURE convert_number
    (    str: string (4);
     VAR value: 1 .. 9999;
     VAR status: ost$status);

    VAR
      int: clt$integer;

    status.normal := TRUE;
    IF str = ' ' THEN
      osp$set_status_condition (ame$section_out_of_sequence, status);
    ELSE
      clp$convert_string_to_integer (str, int, status);
      IF status.normal THEN
        value := int.value;
      ELSE
        osp$set_status_condition (ame$section_out_of_sequence, status);
      IFEND;
    IFEND;

  PROCEND convert_number;
?? OLDTITLE ??
?? NEWTITLE := '    date_is_valid ', EJECT ??

  FUNCTION [UNSAFE] date_is_valid
    (    date: string ( * )): boolean;

    VAR
      date_time: clt$date_time,
      date_string: string (7),
      local_status: ost$status;

{
{ The date field is xYYOOO, where x is [' ' or digit], and YYOOO is Julian Date.

    IF (date = ' ') OR (date = ' 00000') OR (date = '000000') THEN
      date_is_valid := TRUE; {Allow date field to be SPACE or expired}
    ELSE
      IF date (1, 1) = ' ' THEN
        date_string (1, 2) := '19';
        date_string (3, 5) := date (2, 5);
      ELSE
        date_string (1, 1):= '2';
        date_string (2, 6) := date (1, 6);
      IFEND;
      clp$convert_string_to_date_time (date_string, 'Y4J3', date_time, local_status);
      date_is_valid := local_status.normal;
    IFEND;

  FUNCEND date_is_valid;
?? OLDTITLE ??
?? NEWTITLE := '    dismount_current_volume ', EJECT ??

  PROCEDURE dismount_current_volume
    (    file_identifier: amt$file_identifier;
         layer_number: amt$fap_layer_number;
     VAR status: ost$status);

    VAR
      local_call_block: amt$call_block;

    status.normal := TRUE;

    local_call_block.operation := amc$dismount_current_volume;
    amp$access_method (file_identifier, local_call_block, layer_number, status);

  PROCEND dismount_current_volume;
?? OLDTITLE ??
?? NEWTITLE := '    enforce_epix_security', EJECT ??

  PROCEDURE enforce_epix_security
    (    file_accessibility: string (1);
         implementation_identifier: string (13);
         user_is_owner: boolean;
         volume_accessibility: string (1);
     VAR authorized_access {input,output} : fst$file_access_options;
     VAR epix_tape: boolean;
     VAR file_set_access {input,output} : fst$file_access_options);

{Design:
{
{    VA:                        FILE_SET_ACCESS
{    ---------------------------------------
{    blank                      (READ, WRITE)
{      0     (owner access)     (READ, WRITE)
{      0     (nonowner access)  ()
{      1                        (WRITE)
{      2                        (READ)
{
{
{    FA:            AUTHORIZED_ACCESS
{    ---------------------------------------
{    blank          (READ, WRITE)
{      0            (READ, WRITE)   (will be ignored, access controlled by VA)
{      1            (WRITE)
{      2            (READ)

    IF implementation_identifier = epix_version_one THEN
      epix_tape := TRUE;
      IF volume_accessibility = ' ' THEN
        file_set_access := file_set_access * (-$fst$file_access_options []);
      ELSEIF volume_accessibility = '0' THEN
        IF user_is_owner THEN
          file_set_access := file_set_access * (-$fst$file_access_options []);
        ELSE
          file_set_access := file_set_access * $fst$file_access_options [];
        IFEND;
      ELSEIF volume_accessibility = '1' THEN
        file_set_access := file_set_access * $fst$file_access_options [fsc$append, fsc$modify, fsc$shorten];
      ELSEIF volume_accessibility = '2' THEN
        file_set_access := file_set_access * $fst$file_access_options [fsc$execute, fsc$read];
      IFEND;

      IF file_accessibility = ' ' THEN
        authorized_access := authorized_access * (-$fst$file_access_options []);
      ELSEIF file_accessibility = '0' THEN
        authorized_access := authorized_access * (-$fst$file_access_options []);
      ELSEIF file_accessibility = '1' THEN
        authorized_access := authorized_access * $fst$file_access_options [fsc$append, fsc$modify,
              fsc$shorten];
      ELSEIF file_accessibility = '2' THEN
        authorized_access := authorized_access * $fst$file_access_options [fsc$execute, fsc$read];
      IFEND;
    ELSE
      epix_tape := FALSE;
      {File_set_access and authorized_access are not changed
    IFEND;
  PROCEND enforce_epix_security;
?? OLDTITLE ??
?? NEWTITLE := '    get_explicit_attributes', EJECT ??

  PROCEDURE get_explicit_attributes
    (    file: fst$resolved_file_reference;
     VAR explicit_fa: string (1);
     VAR explicit_group: string (13);
     VAR explicit_oi: string (14);
     VAR explicit_va: string (1);
     VAR returned_attributes: fst$tla_returned_attributes;
     VAR status: ost$status);

    CONST
      fa = 1,
      oi = 2,
      rmg = 3,
      va = 4;

    VAR
      explicit_attrib: ^array [fa .. va] of fst$attachment_option,
      local_status: ost$status;

    PUSH explicit_attrib;

    explicit_attrib^ [fa].selector := fsc$tape_attachment;
    explicit_attrib^ [fa].tape_attachment.selector := fsc$tape_file_accessibility;
    explicit_attrib^ [oi].selector := fsc$tape_attachment;
    explicit_attrib^ [oi].tape_attachment.selector := fsc$tape_owner_identification;
    explicit_attrib^ [rmg].selector := fsc$tape_attachment;
    explicit_attrib^ [rmg].tape_attachment.selector := fsc$tape_removable_media_group;
    explicit_attrib^ [va].selector := fsc$tape_attachment;
    explicit_attrib^ [va].tape_attachment.selector := fsc$tape_volume_accessibility;
    fsp$get_tape_label_attributes (file.path (1, file.file_path_size), fsc$tla_explicit_specification,
          explicit_attrib^, returned_attributes, local_status);
    IF local_status.normal THEN
      explicit_fa := explicit_attrib^ [fa].tape_attachment.tape_file_accessibility;
      explicit_group := explicit_attrib^ [rmg].tape_attachment.tape_removable_media_group;
      explicit_oi := explicit_attrib^ [oi].tape_attachment.tape_owner_identification;
      explicit_va := explicit_attrib^ [va].tape_attachment.tape_volume_accessibility;
    IFEND;
  PROCEND get_explicit_attributes;
?? OLDTITLE ??
?? NEWTITLE := '    field_is_numeric ', EJECT ??

  FUNCTION field_is_numeric
    (    field: string ( * )): boolean;

    VAR
      numeric_characters: [STATIC, READ, oss$job_paged_literal] set of char := ['0', '1', '2', '3', '4', '5',
            '6', '7', '8', '9'];

    VAR
      i: integer;

    field_is_numeric := TRUE;
    IF field = ' ' THEN
      RETURN; {Allow numeric field to be SPACE; the volume may be blank labeled}
    IFEND;
    FOR i := 1 TO STRLENGTH (field) DO
      IF NOT (field (i, 1) IN numeric_characters) THEN
        field_is_numeric := FALSE;
        RETURN;
      IFEND;
    FOREND;
  FUNCEND field_is_numeric;
?? OLDTITLE ??
?? NEWTITLE := '    file_accessibility_matches', EJECT ??

  FUNCTION [INLINE] file_accessibility_matches
    (    existing_fa: string (1);
         requested_fa: string (1)): boolean;

    IF existing_fa = requested_fa THEN
      file_accessibility_matches := TRUE;
    ELSEIF existing_fa = ' ' THEN
      file_accessibility_matches := TRUE;
    ELSE
      file_accessibility_matches := FALSE;
    IFEND;

  FUNCEND file_accessibility_matches;
?? OLDTITLE ??
?? NEWTITLE := '    get_boolean_variable', EJECT ??

  PROCEDURE get_boolean_variable
    (    variable: string ( * );
     VAR boolean_value: boolean);

    VAR
      ignore_access_mode: clt$data_access_mode,
      ignore_class: clt$variable_class,
      ignore_evaluation_method: clt$expression_eval_method,
      ignore_type_specification_p: ^clt$type_specification,
      local_status: ost$status,
      value_p: ^clt$data_value,
      work_area_p: ^SEQ ( * );

    local_status.normal := TRUE;

    boolean_value := FALSE;
    PUSH work_area_p: [[REP 1000 OF cell]];
    clp$get_variable (variable, work_area_p, ignore_class, ignore_access_mode, ignore_evaluation_method,
          ignore_type_specification_p, value_p, local_status);
    IF local_status.normal THEN
      IF value_p^.kind = clc$boolean THEN
        boolean_value := value_p^.boolean_value.value;
      IFEND;
    IFEND;

  PROCEND get_boolean_variable;
?? OLDTITLE ??
?? NEWTITLE := '    get_login_identification', EJECT ??

  PROCEDURE get_login_identification
    (VAR account: avt$account_name;
     VAR family: ost$family_name;
     VAR project: avt$project_name;
     VAR user: ost$user_name;
     VAR status: ost$status);

    VAR
      identification: ost$user_identification;

    account := osc$null_name;
    family := osc$null_name;
    project := osc$null_name;
    user := osc$null_name;

    pmp$get_user_identification (identification, status);
    IF status.normal THEN
      family := identification.family;
      user := identification.user;
      pmp$get_account_project (account, project, status);
    IFEND;

  PROCEND get_login_identification;
?? OLDTITLE ??
?? NEWTITLE := '    get_user_identification', EJECT ??

  PROCEDURE get_user_identification
    (    file: fst$resolved_file_reference;
     VAR family: ost$family_name;
     VAR user: ost$user_name;
     VAR status: ost$status);

{Design: If a reference to a volume is made through a temporary file, the
{relevant family/user is the login-user; otherwise, it is the family/user of the
{permanent file path.

    VAR
      identification: ost$user_identification;

    IF file.permanent_file THEN
      family := file.path (file.family_name.index, file.family_name.size);
      user := file.path (file.master_catalog_name.index, file.master_catalog_name.size);
    ELSE
      pmp$get_user_identification (identification, status);
      family := identification.family;
      user := identification.user;
    IFEND;

  PROCEND get_user_identification;
?? OLDTITLE ??
?? NEWTITLE := '    log_ansi_label', EJECT ??

  PROCEDURE log_ansi_label
    (    condition: ost$status_condition_code;
         file: fst$file_reference;
         label: string ( * ));

    VAR
      ignore_status: ost$status,
      logset: pmt$ascii_logset,
      log_message_status: ost$status;

    IF log_labels THEN
      osp$set_status_condition (condition, log_message_status);
      osp$append_status_file (osc$status_parameter_delimiter, file, log_message_status);
      osp$append_status_parameter (osc$status_parameter_delimiter, label, log_message_status);
      logset := $pmt$ascii_logset [pmc$job_log];
      osp$generate_log_message (logset, log_message_status, ignore_status);
    IFEND;
  PROCEND log_ansi_label;
?? OLDTITLE ??
?? NEWTITLE := '    log_erroneous_block', EJECT ??

  PROCEDURE log_erroneous_block
    (    file: fst$file_reference;
         locator: fst$tape_label_locator);

    VAR
      error_block: ^string ( * ),
      ignore_status: ost$status,
      length: integer,
      logset: pmt$ascii_logset,
      log_message_status: ost$status,
      sequence: ^SEQ ( * );

    osp$set_status_condition (ame$log_error_block, log_message_status);

    osp$append_status_file (osc$status_parameter_delimiter, file, log_message_status);

    IF locator.label_block_descriptor^.erroneous_label_transfer_length < 80 THEN
      length := locator.label_block_descriptor^.erroneous_label_transfer_length;
    ELSE
      length := 80;
    IFEND;

    IF (length > 0) AND (locator.label_block <> NIL) THEN
      sequence := locator.label_block;
      RESET sequence;
      NEXT error_block: [length] IN sequence;
      IF error_block <> NIL THEN
        osp$append_status_parameter (osc$status_parameter_delimiter, error_block^ (1, length),
              log_message_status);
      ELSE
        osp$append_status_parameter (osc$status_parameter_delimiter, ' ** No Data Read **' ,
              log_message_status);
      IFEND;
    ELSE
      osp$append_status_parameter (osc$status_parameter_delimiter, ' ** No Data Read **' ,
            log_message_status);
    IFEND;

    logset := $pmt$ascii_logset [pmc$job_log];
    osp$generate_log_message (logset, log_message_status, ignore_status);

  PROCEND log_erroneous_block;
?? OLDTITLE ??
?? NEWTITLE := '    log_non_label_block', EJECT ??

  PROCEDURE log_non_label_block
    (    file: fst$file_reference;
         locator: fst$tape_label_locator);

    VAR
      ignore_status: ost$status,
      length: integer,
      logset: pmt$ascii_logset,
      log_message_status: ost$status,
      non_label_block: ^string ( * ),
      sequence: ^SEQ ( * );

    osp$set_status_condition (ame$log_non_label_block, log_message_status);

    osp$append_status_file (osc$status_parameter_delimiter, file, log_message_status);

    IF locator.label_block_descriptor^.non_label_transfer_length < 80 THEN
      length := locator.label_block_descriptor^.non_label_transfer_length;
    ELSE
      length := 80;
    IFEND;

    IF (length > 0) AND (locator.label_block <> NIL) THEN
      sequence := locator.label_block;
      RESET sequence;
      NEXT non_label_block: [length] IN sequence;
      IF non_label_block <> NIL THEN
        osp$append_status_parameter (osc$status_parameter_delimiter, non_label_block^ (1, length),
              log_message_status);
      ELSE
        osp$append_status_parameter (osc$status_parameter_delimiter, ' ** No Data Read **' ,
              log_message_status);
      IFEND;
    ELSE
      osp$append_status_parameter (osc$status_parameter_delimiter, ' ** No Data Read **' ,
            log_message_status);
    IFEND;

    logset := $pmt$ascii_logset [pmc$job_log];
    osp$generate_log_message (logset, log_message_status, ignore_status);

  PROCEND log_non_label_block;
?? OLDTITLE ??
?? NEWTITLE := '    log_improper_block_count', EJECT ??

  PROCEDURE log_improper_block_count
    (    field_name: string ( * );
         file: fst$file_reference;
         label_name: string ( * );
         original_field_value: string ( * );
         new_field_value: string ( * ));

    VAR
      ignore_status: ost$status,
      logset: pmt$ascii_logset,
      log_message_status: ost$status;

    osp$set_status_condition (ame$improper_block_count, log_message_status);
    osp$append_status_file (osc$status_parameter_delimiter, file, log_message_status);
    osp$append_status_parameter (osc$status_parameter_delimiter, field_name, log_message_status);
    osp$append_status_parameter (osc$status_parameter_delimiter, label_name, log_message_status);
    osp$append_status_parameter (osc$status_parameter_delimiter, original_field_value, log_message_status);
    osp$append_status_parameter (osc$status_parameter_delimiter, new_field_value, log_message_status);
    logset := $pmt$ascii_logset [pmc$job_log];
    osp$generate_log_message (logset, log_message_status, ignore_status);

  PROCEND log_improper_block_count;
?? OLDTITLE ??
?? NEWTITLE := '    log_improper_label_field', EJECT ??

  PROCEDURE log_improper_label_field
    (    field_name: string ( * );
         file: fst$file_reference;
         label_name: string ( * );
         original_field_value: string ( * ));

    VAR
      ignore_status: ost$status,
      logset: pmt$ascii_logset,
      log_message_status: ost$status;

    osp$set_status_condition (ame$improper_label_field, log_message_status);
    osp$append_status_file (osc$status_parameter_delimiter, file, log_message_status);
    osp$append_status_parameter (osc$status_parameter_delimiter, field_name, log_message_status);
    osp$append_status_parameter (osc$status_parameter_delimiter, label_name, log_message_status);
    osp$append_status_parameter (osc$status_parameter_delimiter, original_field_value, log_message_status);
    logset := $pmt$ascii_logset [pmc$job_log];
    osp$generate_log_message (logset, log_message_status, ignore_status);

  PROCEND log_improper_label_field;
?? OLDTITLE ??
?? NEWTITLE := '    log_invalid_date_field', EJECT ??

  PROCEDURE log_invalid_date_field
    (    field_name: string ( * );
         file: fst$file_reference;
         label_name: string ( * );
         original_field_value: string ( * ));

    VAR
      ignore_status: ost$status,
      logset: pmt$ascii_logset,
      log_message_status: ost$status;

    osp$set_status_condition (ame$invalid_date_field, log_message_status);
    osp$append_status_file (osc$status_parameter_delimiter, file, log_message_status);
    osp$append_status_parameter (osc$status_parameter_delimiter, field_name, log_message_status);
    osp$append_status_parameter (osc$status_parameter_delimiter, label_name, log_message_status);
    osp$append_status_parameter (osc$status_parameter_delimiter, original_field_value, log_message_status);
    IF field_name (16) = 'C' THEN { Creation Date }
      osp$append_status_parameter (osc$status_parameter_delimiter, 'CREATION_DATE', log_message_status);
      osp$append_status_parameter (osc$status_parameter_delimiter, 'SPACE', log_message_status);
    ELSE { Expiration Date }
      osp$append_status_parameter (osc$status_parameter_delimiter, 'EXPIRATION_DATE', log_message_status);
      osp$append_status_parameter (osc$status_parameter_delimiter, ''' 00000'' (expired)',
            log_message_status);
    IFEND;
    logset := $pmt$ascii_logset [pmc$job_log];
    osp$generate_log_message (logset, log_message_status, ignore_status);

  PROCEND log_invalid_date_field;
?? OLDTITLE ??
?? NEWTITLE := '    log_nonnumeric_label_field', EJECT ??

  PROCEDURE log_nonnumeric_label_field
    (    field_name: string ( * );
         file: fst$file_reference;
         label_name: string ( * );
         original_field_value: string ( * ));

    VAR
      ignore_status: ost$status,
      logset: pmt$ascii_logset,
      log_message_status: ost$status;

    osp$set_status_condition (ame$label_field_not_numeric, log_message_status);
    osp$append_status_file (osc$status_parameter_delimiter, file, log_message_status);
    osp$append_status_parameter (osc$status_parameter_delimiter, field_name, log_message_status);
    osp$append_status_parameter (osc$status_parameter_delimiter, label_name, log_message_status);
    osp$append_status_parameter (osc$status_parameter_delimiter, original_field_value, log_message_status);
    logset := $pmt$ascii_logset [pmc$job_log];
    osp$generate_log_message (logset, log_message_status, ignore_status);

  PROCEND log_nonnumeric_label_field;
?? OLDTITLE ??
?? NEWTITLE := '    owner_identifier_matches', EJECT ??

  FUNCTION [INLINE] owner_identifier_matches
    (    existing_oi: string ( * );
         requested_oi: string ( * )): boolean;

    IF existing_oi = requested_oi THEN
      owner_identifier_matches := TRUE;
    ELSEIF existing_oi = ' ' THEN
      owner_identifier_matches := TRUE;
    ELSE
      owner_identifier_matches := FALSE;
    IFEND;

  FUNCEND owner_identifier_matches;
?? OLDTITLE ??
?? NEWTITLE := '    secure_header_labels ', EJECT ??

  PROCEDURE secure_header_labels
    (    file: fst$file_reference;
         file_identifier: amt$file_identifier;
         request: fst$ts_secure_header_labels;
         layer_number: amt$fap_layer_number;
     VAR status: ost$status);

    VAR
      hdr1_label: ^fst$ansi_hdr1_label,
      header_labels: ^SEQ ( * ),
      label_identifier: fst$tape_label_identifier,
      label_locator: fst$tape_label_locator,
      label_string: ^string (80),
      vol1_label: ^fst$ansi_vol1_label;

    status.normal := TRUE;
    header_labels := request.header_labels;
    RESET header_labels;

    label_identifier.location_method := fsc$tape_label_locate_by_index;
    label_identifier.label_index := 1;
    REPEAT
      fsp$locate_tape_label (header_labels, label_identifier, label_locator);
      IF label_locator.label_found THEN
        CASE label_locator.label_block_descriptor^.label_block_type OF
        = fsc$erroneous_tape_label_block =
          log_erroneous_block (file, label_locator);
        = fsc$non_tape_label_block =
          log_non_label_block (file, label_locator);
        = fsc$normal_tape_label_block =
          RESET label_locator.label_block;
          NEXT label_string IN label_locator.label_block;
          CASE label_locator.label_block_descriptor^.normal_label_kind OF
          = fsc$ansi_vol1_label_kind =
            RESET label_locator.label_block;
            NEXT vol1_label IN label_locator.label_block;
            IF vol1_label <> NIL THEN
              IF avp$removable_media_admin () THEN
                log_ansi_label (ame$log_vol1_label, file, label_string^ (1, 80));
                vol1_label^.owner_identifier := ' ';
                vol1_label^.accessibility := ' ';
              ELSE
                vol1_label^.owner_identifier := ' ';
                vol1_label^.accessibility := ' ';
                log_ansi_label (ame$log_vol1_label, file, label_string^ (1, 80));
              IFEND;
            IFEND;
          = fsc$ansi_hdr1_label_kind =
            RESET label_locator.label_block;
            NEXT hdr1_label IN label_locator.label_block;
            IF hdr1_label <> NIL THEN
              IF avp$removable_media_admin () THEN
                log_ansi_label (ame$log_ansi1_label, file, label_string^ (1, 80));
                hdr1_label^.accessibility := ' ';
              ELSE
                hdr1_label^.accessibility := ' ';
                log_ansi_label (ame$log_ansi1_label, file, label_string^ (1, 80));
              IFEND;
            IFEND;
          = fsc$ansi_hdr2_label_kind =
            log_ansi_label (ame$log_ansi2_label, file, label_string^ (1, 80));
          ELSE
            log_ansi_label (ame$log_ansix_label, file, label_string^ (1, 80));
          CASEND;
        ELSE
        CASEND;
        label_identifier.label_index := label_identifier.label_index + 1;
      IFEND;
    UNTIL NOT label_locator.label_found;
  PROCEND secure_header_labels;
?? OLDTITLE ??
?? NEWTITLE := '    secure_trailer_labels ', EJECT ??

  PROCEDURE secure_trailer_labels
    (    file: fst$file_reference;
         file_identifier: amt$file_identifier;
         request: fst$ts_secure_trailer_labels;
         layer_number: amt$fap_layer_number;
     VAR status: ost$status);

    VAR
      eof1_label: ^fst$ansi_eof1_label,
      label_identifier: fst$tape_label_identifier,
      label_locator: fst$tape_label_locator,
      label_string: ^string (80),
      trailer_labels: ^SEQ ( * );

    status.normal := TRUE;
    trailer_labels := request.trailer_labels;
    RESET trailer_labels;

    label_identifier.location_method := fsc$tape_label_locate_by_index;
    label_identifier.label_index := 1;
    REPEAT
      fsp$locate_tape_label (trailer_labels, label_identifier, label_locator);
      IF label_locator.label_found THEN
        CASE label_locator.label_block_descriptor^.label_block_type OF
        = fsc$erroneous_tape_label_block =
          log_erroneous_block (file, label_locator);
        = fsc$non_tape_label_block =
          log_non_label_block (file, label_locator);
        = fsc$normal_tape_label_block =
          RESET label_locator.label_block;
          NEXT label_string IN label_locator.label_block;
          CASE label_locator.label_block_descriptor^.normal_label_kind OF
          = fsc$ansi_eof1_label_kind, fsc$ansi_eov1_label_kind =
            RESET label_locator.label_block;
            NEXT eof1_label IN label_locator.label_block;
            IF eof1_label <> NIL THEN
              IF avp$removable_media_admin () THEN
                log_ansi_label (ame$log_ansi1_label, file, label_string^ (1, 80));
                eof1_label^.accessibility := ' ';
              ELSE
                eof1_label^.accessibility := ' ';
                log_ansi_label (ame$log_ansi1_label, file, label_string^ (1, 80));
              IFEND;
            IFEND;
          = fsc$ansi_eof2_label_kind, fsc$ansi_eov2_label_kind =
            log_ansi_label (ame$log_ansi2_label, file, label_string^ (1, 80));
          ELSE
            log_ansi_label (ame$log_ansix_label, file, label_string^ (1, 80));
          CASEND;
        ELSE
        CASEND;
        label_identifier.label_index := label_identifier.label_index + 1;
      IFEND;
    UNTIL NOT label_locator.label_found;

  PROCEND secure_trailer_labels;
?? OLDTITLE ??
?? NEWTITLE := '    validate_eox1_label ', EJECT ??

  PROCEDURE validate_eox1_label
    (    file: fst$file_reference;
         file_identifier: amt$file_identifier;
         layer_number: amt$fap_layer_number;
     VAR eox1: fst$ansi_eof1_label;
     VAR status: ost$status);

{Design:
{Each numeric field in the EOF1 or EOV1 label is validated to be a number or SPACE.  Each
{a-character (i.e. text) field that contains control information is validated to
{contain a legal value, including SPACE.  Any invalid field is set to SPACE.  This
{allows the field to be under control of the NOS/VE user through specification of
{file attributes.}
?? EJECT ??
    status.normal := TRUE;
    IF NOT (field_is_numeric (eox1.file_section_number)) THEN
      log_nonnumeric_label_field ('Bytes 28..31 - File Section Number', file, eox1.label_identifier,
            eox1.file_section_number);
      eox1.file_section_number := ' ';
    IFEND;
    IF NOT (field_is_numeric (eox1.file_sequence_number)) THEN
      log_nonnumeric_label_field ('Bytes 32..35 - File Sequence Number', file, eox1.label_identifier,
            eox1.file_sequence_number);
      eox1.file_sequence_number := ' ';
    IFEND;
    IF NOT (field_is_numeric (eox1.generation_number)) THEN
      log_nonnumeric_label_field ('Bytes 36..39 - Generation Number', file, eox1.label_identifier,
            eox1.generation_number);
      eox1.generation_number := ' ';
    IFEND;
    IF NOT (field_is_numeric (eox1.generation_version_number)) THEN
      log_nonnumeric_label_field ('Bytes 40..41 - Generation Version Number', file, eox1.label_identifier,
            eox1.generation_version_number);
      eox1.generation_version_number := ' ';
    IFEND;
    IF NOT (date_is_valid (eox1.creation_date)) THEN
      log_invalid_date_field ('Bytes 42..47 - Creation Date', file, eox1.label_identifier,
            eox1.creation_date);
      eox1.creation_date := ' ';
    IFEND;
    IF NOT (date_is_valid (eox1.expiration_date)) THEN
      log_invalid_date_field ('Bytes 48..53 - Expiration Date', file, eox1.label_identifier,
            eox1.expiration_date);
      eox1.expiration_date := ' 00000';
    IFEND;
    IF NOT (field_is_numeric (eox1.block_count)) THEN
      log_nonnumeric_label_field ('Bytes 55..60 - Block Count', file, eox1.label_identifier,
            eox1.block_count);
      eox1.block_count := ' ';
    IFEND;

  PROCEND validate_eox1_label;
?? OLDTITLE ??
?? NEWTITLE := '    validate_eox2_label ', EJECT ??

  PROCEDURE validate_eox2_label
    (    eox1: fst$ansi_eof1_label;
         file: fst$file_reference;
         file_identifier: amt$file_identifier;
         layer_number: amt$fap_layer_number;
     VAR eox2 {input,output} : fst$ansi_eof2_label;
     VAR status: ost$status);

{Design:
{Each numeric field in the EOF1 or EOV1 label is validated to be a number or SPACE.  Each
{a-character (i.e. text) field that contains control information is validated to
{contain a legal value, including SPACE.  Any invalid field is set to SPACE.  This
{allows the field to be under control of the NOS/VE user through specification of
{file attributes.}
?? EJECT ??
    status.normal := TRUE;
    IF NOT (eox2.record_format IN ve_record_types) THEN
      log_improper_label_field ('Byte 5 - Record Format', file, eox2.label_identifier, eox2.record_format);
      eox2.record_format := ' ';
    IFEND;
    IF NOT (field_is_numeric (eox2.block_length)) THEN
      log_nonnumeric_label_field ('Bytes 6..10 - Block Length', file, eox2.label_identifier,
            eox2.block_length);
      eox2.block_length := ' ';
    IFEND;
    IF NOT (field_is_numeric (eox2.record_length)) THEN
      log_nonnumeric_label_field ('Bytes 11..15 - Record Length', file, eox2.label_identifier,
            eox2.record_length);
      eox2.record_length := ' ';
    IFEND;
    IF fsp$ve_wrote_ansi_file (eox1.system_code) THEN
      IF NOT ((eox2.ve_block_type = ' ') OR (eox2.ve_block_type = 'SS') OR (eox2.ve_block_type = 'US')) THEN
        log_improper_label_field ('Bytes 16..17 - NOS/VE block_type', file, eox2.label_identifier,
              eox2.ve_block_type);
        eox2.ve_block_type := ' ';
      IFEND;
      IF NOT (eox2.ve_record_type IN ve_record_types) THEN
        log_improper_label_field ('Byte 18 - NOS/VE record_type', file, eox2.label_identifier,
              eox2.ve_record_type);
        eox2.ve_record_type := ' ';
      IFEND;
      IF NOT (field_is_numeric (eox2.ve_block_length_ext)) THEN
        log_nonnumeric_label_field ('Bytes 19..21 - NOS/VE block_length_extension', file,
              eox2.label_identifier, eox2.ve_block_length_ext);
        eox2.ve_block_length_ext := ' ';
      IFEND;
      IF NOT (field_is_numeric (eox2.ve_record_length_ext)) THEN
        log_nonnumeric_label_field ('Bytes 22..24 - NOS/VE record_length_extension', file,
              eox2.label_identifier, eox2.ve_record_length_ext);
        eox2.ve_record_length_ext := ' ';
      IFEND;
      IF NOT (eox2.ve_character_set IN ve_character_sets) THEN
        log_improper_label_field ('Byte 26 - NOS/VE character_set', file, eox2.label_identifier,
              eox2.ve_character_set);
        eox2.ve_character_set := ' ';
      IFEND;
      IF NOT (eox2.ve_character_conversion IN ve_character_conversions) THEN
        log_improper_label_field ('Byte 27 - NOS/VE character_conversion', file, eox2.label_identifier,
              eox2.ve_character_conversion);
        eox2.ve_character_conversion := ' ';
      IFEND;
    IFEND;
    IF NOT (field_is_numeric (eox2.buffer_offset_length)) THEN
      log_nonnumeric_label_field ('Bytes 51..52 - Offset Length', file, eox2.label_identifier,
            eox2.buffer_offset_length);
      eox2.buffer_offset_length := ' ';
    IFEND;

  PROCEND validate_eox2_label;
?? OLDTITLE ??
?? NEWTITLE := '    validate_header_labels ', EJECT ??

  PROCEDURE validate_header_labels
    (    file: fst$file_reference;
         file_identifier: amt$file_identifier;
         request: fst$ts_validate_header_labels;
         layer_number: amt$fap_layer_number;
     VAR status: ost$status);

    VAR
      hdr1_label: ^fst$ansi_hdr1_label,
      hdr2_label: ^fst$ansi_hdr2_label,
      header_labels: ^SEQ ( * ),
      label_identifier: fst$tape_label_identifier,
      label_locator: fst$tape_label_locator,
      vol1_label: ^fst$ansi_vol1_label;

    status.normal := TRUE;
    hdr1_label := NIL;
    hdr2_label := NIL;
    vol1_label := NIL;

    header_labels := request.header_labels;
    RESET header_labels;
    label_identifier.location_method := fsc$tape_label_locate_by_kind;
    label_identifier.label_kind := fsc$ansi_vol1_label_kind;
    fsp$locate_tape_label (header_labels, label_identifier, label_locator);
    IF label_locator.label_found AND (label_locator.label_block <> NIL) THEN
      RESET label_locator.label_block;
      NEXT vol1_label IN label_locator.label_block;
      IF vol1_label <> NIL THEN
        validate_vol1_label (file, file_identifier, layer_number, vol1_label^, status);
      IFEND;
    IFEND;
    IF status.normal THEN
      label_identifier.location_method := fsc$tape_label_locate_by_kind;
      label_identifier.label_kind := fsc$ansi_hdr1_label_kind;
      fsp$locate_tape_label (header_labels, label_identifier, label_locator);
      IF label_locator.label_found AND (label_locator.label_block <> NIL) THEN
        RESET label_locator.label_block;
        NEXT hdr1_label IN label_locator.label_block;
        IF hdr1_label <> NIL THEN
          validate_hdr1_label (file, file_identifier, layer_number, hdr1_label^, status);
        IFEND;
      IFEND;
    IFEND;
    IF status.normal THEN
      label_identifier.location_method := fsc$tape_label_locate_by_kind;
      label_identifier.label_kind := fsc$ansi_hdr2_label_kind;
      fsp$locate_tape_label (header_labels, label_identifier, label_locator);
      IF label_locator.label_found AND (label_locator.label_block <> NIL) THEN
        RESET label_locator.label_block;
        NEXT hdr2_label IN label_locator.label_block;
        IF hdr2_label <> NIL THEN
          validate_hdr2_label (file, file_identifier, hdr1_label, layer_number, hdr2_label^, status);
        IFEND;
      IFEND;
    IFEND;
  PROCEND validate_header_labels;
?? OLDTITLE ??
?? NEWTITLE := '    validate_hdr1_label ', EJECT ??

  PROCEDURE validate_hdr1_label
    (    file: fst$file_reference;
         file_identifier: amt$file_identifier;
         layer_number: amt$fap_layer_number;
     VAR hdr1: fst$ansi_hdr1_label;
     VAR status: ost$status);

{Design:
{Each numeric field in the HDR1 label is validated to be a number or SPACE.
{Any invalid field is set to SPACE.  This allows the field to be under control
{of the NOS/VE user through specification of file attributes.}
?? EJECT ??
    VAR
      local_status: ost$status;

    status.normal := TRUE;
    rmp$validate_ansi_string (hdr1.file_identifier, hdr1.file_identifier, local_status);
    IF NOT local_status.normal THEN
      log_improper_label_field ('FILE_IDENTIFIER', file, 'HDR1', hdr1.file_identifier);
      hdr1.file_identifier := ' ';
    IFEND;
    rmp$validate_ansi_string (hdr1.file_set_identifier, hdr1.file_set_identifier, local_status);
    IF NOT local_status.normal THEN
      log_improper_label_field ('FILE_SET_IDENTIFIER', file, 'HDR1', hdr1.file_set_identifier);
      hdr1.file_set_identifier := ' ';
    IFEND;
    IF NOT (field_is_numeric (hdr1.file_section_number)) THEN
      log_nonnumeric_label_field ('Bytes 28..31 - File Section Number', file, 'HDR1',
            hdr1.file_section_number);
      hdr1.file_section_number := ' ';
    IFEND;
    IF NOT (field_is_numeric (hdr1.file_sequence_number)) THEN
      log_nonnumeric_label_field ('Bytes 32..35 - File Sequence Number', file, 'HDR1',
            hdr1.file_sequence_number);
      hdr1.file_sequence_number := ' ';
    IFEND;
    IF NOT (field_is_numeric (hdr1.generation_number)) THEN
      log_nonnumeric_label_field ('Bytes 36..39 - Generation Number', file, 'HDR1', hdr1.generation_number);
      hdr1.generation_number := ' ';
    IFEND;
    IF NOT (field_is_numeric (hdr1.generation_version_number)) THEN
      log_nonnumeric_label_field ('Bytes 40..41 - Generation Version Number', file, 'HDR1',
            hdr1.generation_version_number);
      hdr1.generation_version_number := ' ';
    IFEND;
    IF NOT (date_is_valid (hdr1.creation_date)) THEN
      log_invalid_date_field ('Bytes 42..47 - Creation Date', file, 'HDR1', hdr1.creation_date);
      hdr1.creation_date := ' ';
    IFEND;
    IF NOT (date_is_valid (hdr1.expiration_date)) THEN
      log_invalid_date_field ('Bytes 48..53 - Expiration Date', file, 'HDR1', hdr1.expiration_date);
      hdr1.expiration_date := ' 00000';
    IFEND;
    rmp$validate_ansi_string (hdr1.accessibility, hdr1.accessibility, local_status);
    IF NOT local_status.normal THEN
      log_improper_label_field ('FILE_ACCESSIBILITY', file, 'HDR1', hdr1.accessibility);
      hdr1.accessibility := ' ';
    IFEND;
    IF NOT (field_is_numeric (hdr1.block_count)) THEN
      log_improper_block_count ('Bytes 55..60 - Block Count', file, 'HDR1', hdr1.block_count, '000000');
      hdr1.block_count := '000000';
    IFEND;
    rmp$validate_ansi_string (hdr1.system_code, hdr1.system_code, local_status);
    IF NOT local_status.normal THEN
      log_improper_label_field ('IMPLEMENTATION_IDENTIFIER', file, 'HDR1', hdr1.system_code);
      hdr1.system_code := ' ';
    IFEND;

  PROCEND validate_hdr1_label;
?? OLDTITLE ??
?? NEWTITLE := '    validate_hdr2_label ', EJECT ??

  PROCEDURE validate_hdr2_label
    (    file: fst$file_reference;
         file_identifier: amt$file_identifier;
         hdr1: ^fst$ansi_hdr1_label;
         layer_number: amt$fap_layer_number;
     VAR hdr2: fst$ansi_hdr2_label;
     VAR status: ost$status);

{Design:
{Each numeric field in the HDR2 label is validated to be a number or SPACE.
{Any invalid field is set to SPACE.  This allows the field to be under control
{of the NOS/VE user through specification of file attributes.}
{file attributes.  If NOS/VE wrote the HDR labels, values in bytes 16..27 which are
{reserved to implementors of the ANSI standard are validated for legal NOS/VE values.}
?? EJECT ??
    status.normal := TRUE;
    IF NOT (hdr2.record_format IN ve_record_types) OR (hdr2.record_format = 'U') OR
          (hdr2.record_format = 'u') THEN
      log_improper_label_field ('Byte 5 - Record Format', file, 'HDR2', hdr2.record_format);
      hdr2.record_format := ' ';
    IFEND;
    IF NOT (field_is_numeric (hdr2.block_length)) THEN
      log_nonnumeric_label_field ('Bytes 6..10 - Block Length', file, 'HDR2', hdr2.block_length);
      hdr2.block_length := ' ';
    IFEND;
    IF NOT (field_is_numeric (hdr2.record_length)) THEN
      log_nonnumeric_label_field ('Bytes 11..15 - Record Length', file, 'HDR2', hdr2.record_length);
      hdr2.record_length := ' ';
    IFEND;
    IF (hdr1 <> NIL) AND fsp$ve_wrote_ansi_file (hdr1^.system_code) THEN
      IF NOT ((hdr2.ve_block_type = ' ') OR (hdr2.ve_block_type = 'SS') OR (hdr2.ve_block_type = 'US')) THEN
        log_improper_label_field ('Bytes 16..17 - NOS/VE block_type', file, 'HDR2', hdr2.ve_block_type);
        hdr2.ve_block_type := ' ';
      IFEND;
      IF NOT (hdr2.ve_record_type IN ve_record_types) THEN
        log_improper_label_field ('Byte 18 - NOS/VE record_type', file, 'HDR2', hdr2.ve_record_type);
        hdr2.ve_record_type := ' ';
      IFEND;
      IF NOT (field_is_numeric (hdr2.ve_block_length_ext)) THEN
        log_nonnumeric_label_field ('Bytes 19..21 - NOS/VE block_length_extension', file, 'HDR2',
              hdr2.ve_block_length_ext);
        hdr2.ve_block_length_ext := ' ';
      IFEND;
      IF NOT (field_is_numeric (hdr2.ve_record_length_ext)) THEN
        log_nonnumeric_label_field ('Bytes 22..24 - NOS/VE record_length_extension', file, 'HDR2',
              hdr2.ve_record_length_ext);
        hdr2.ve_record_length_ext := ' ';
      IFEND;
      IF NOT (hdr2.ve_character_set IN ve_character_sets) THEN
        log_improper_label_field ('Byte 26 - NOS/VE character_set', file, 'HDR2', hdr2.ve_character_set);
        hdr2.ve_character_set := ' ';
      IFEND;
      IF NOT (hdr2.ve_character_conversion IN ve_character_conversions) THEN
        log_improper_label_field ('Byte 27 - NOS/VE character_conversion', file, 'HDR2',
              hdr2.ve_character_conversion);
        hdr2.ve_character_conversion := ' ';
      IFEND;
    ELSE
      IF hdr2.block_length = '00000' THEN
        log_improper_label_field ('Bytes 6..10 - Block Length', file, 'HDR2', hdr2.block_length);
        hdr2.block_length := ' ';
      IFEND;
      IF hdr2.record_length = '00000' THEN
        log_improper_label_field ('Bytes 11..15 - Record Length', file, 'HDR2', hdr2.record_length);
        hdr2.record_length := ' ';
      IFEND;
    IFEND;
    IF NOT (field_is_numeric (hdr2.buffer_offset_length)) THEN
      log_nonnumeric_label_field ('Bytes 51..52 - Offset Length', file, 'HDR2', hdr2.buffer_offset_length);
      hdr2.buffer_offset_length := ' ';
    IFEND;
  PROCEND validate_hdr2_label;
?? OLDTITLE ??
?? NEWTITLE := '    validate_trailer_labels ', EJECT ??

  PROCEDURE validate_trailer_labels
    (    file: fst$file_reference;
         file_identifier: amt$file_identifier;
         request: fst$ts_validate_trailer_labels;
         layer_number: amt$fap_layer_number;
     VAR status: ost$status);

    VAR
      eox1_label: ^fst$ansi_eof1_label,
      eox2_label: ^fst$ansi_eof2_label,
      label_identifier: fst$tape_label_identifier,
      label_locator: fst$tape_label_locator,
      trailer_labels: ^SEQ ( * );

    status.normal := TRUE;
    trailer_labels := request.trailer_labels;
    RESET trailer_labels;
    label_identifier.location_method := fsc$tape_label_locate_by_kind;
    label_identifier.label_kind := fsc$ansi_eof1_label_kind;
    fsp$locate_tape_label (trailer_labels, label_identifier, label_locator);
    IF label_locator.label_found THEN
      RESET label_locator.label_block;
      NEXT eox1_label IN label_locator.label_block;
      IF eox1_label <> NIL THEN
        validate_eox1_label (file, file_identifier, layer_number, eox1_label^, status);
        IF status.normal THEN
          label_identifier.location_method := fsc$tape_label_locate_by_kind;
          label_identifier.label_kind := fsc$ansi_eof2_label_kind;
          fsp$locate_tape_label (trailer_labels, label_identifier, label_locator);
          IF label_locator.label_found THEN
            RESET label_locator.label_block;
            NEXT eox2_label IN label_locator.label_block;
            IF eox2_label <> NIL THEN
              validate_eox2_label (eox1_label^, file, file_identifier, layer_number, eox2_label^, status);
            IFEND;
          IFEND;
        IFEND;
      IFEND;
    ELSE
      label_identifier.location_method := fsc$tape_label_locate_by_kind;
      label_identifier.label_kind := fsc$ansi_eov1_label_kind;
      fsp$locate_tape_label (trailer_labels, label_identifier, label_locator);
      IF label_locator.label_found THEN
        RESET label_locator.label_block;
        NEXT eox1_label IN label_locator.label_block;
        IF eox1_label <> NIL THEN
          validate_eox1_label (file, file_identifier, layer_number, eox1_label^, status);
          IF status.normal THEN
            label_identifier.location_method := fsc$tape_label_locate_by_kind;
            label_identifier.label_kind := fsc$ansi_eov2_label_kind;
            fsp$locate_tape_label (trailer_labels, label_identifier, label_locator);
            IF label_locator.label_found THEN
              RESET label_locator.label_block;
              NEXT eox2_label IN label_locator.label_block;
              IF eox2_label <> NIL THEN
                validate_eox2_label (eox1_label^, file, file_identifier, layer_number, eox2_label^, status);
              IFEND;
            IFEND;
          IFEND;
        IFEND;
      IFEND;
    IFEND;

  PROCEND validate_trailer_labels;
?? OLDTITLE ??
?? NEWTITLE := '    validate_vol1_label ', EJECT ??

  PROCEDURE validate_vol1_label
    (    file: fst$file_reference;
         file_identifier: amt$file_identifier;
         layer_number: amt$fap_layer_number;
     VAR vol1: fst$ansi_vol1_label;
     VAR status: ost$status);

{Design:
{Each numeric field in the VOL1 label is validated to be a number or SPACE.
?? EJECT ??

    VAR
      local_status: ost$status;

    status.normal := TRUE;

    IF NOT (field_is_numeric (vol1.label_standard_version)) THEN
      log_nonnumeric_label_field ('LABEL_STANDARD_VERSION', file, 'VOL1', vol1.label_standard_version);
      vol1.label_standard_version := ' ';
    IFEND;
    rmp$validate_ansi_string (vol1.volume_identifier, vol1.volume_identifier, local_status);
    IF NOT local_status.normal THEN
      log_improper_label_field ('VOLUME_IDENTIFIER', file, 'VOL1', vol1.volume_identifier);
      vol1.volume_identifier := ' ';
    IFEND;
    rmp$validate_ansi_string (vol1.accessibility, vol1.accessibility, local_status);
    IF NOT local_status.normal THEN
      log_improper_label_field ('VOLUME_ACCESSIBILITY', file, 'VOL1', vol1.accessibility);
      vol1.accessibility := ' ';
    IFEND;
    rmp$validate_ansi_string (vol1.implementation_identifier, vol1.implementation_identifier, local_status);
    IF NOT local_status.normal THEN
      log_improper_label_field ('IMPLEMENTATION_IDENTIFIER', file, 'VOL1', vol1.implementation_identifier);
      vol1.implementation_identifier := ' ';
    IFEND;
    rmp$validate_ansi_string (vol1.owner_identifier, vol1.owner_identifier, local_status);
    IF NOT local_status.normal THEN
      log_improper_label_field ('OWNER_IDENTIFIER', file, 'VOL1', vol1.owner_identifier);
      vol1.owner_identifier := ' ';
    IFEND;

  PROCEND validate_vol1_label;
?? OLDTITLE ??
?? NEWTITLE := '    volume_accessibility_matches', EJECT ??

  FUNCTION [INLINE] volume_accessibility_matches
    (    existing_va: string (1);
         requested_va: string (1)): boolean;

    IF existing_va = requested_va THEN
      volume_accessibility_matches := TRUE;
    ELSEIF existing_va = ' ' THEN
      volume_accessibility_matches := TRUE;
    ELSE
      volume_accessibility_matches := FALSE;
    IFEND;

  FUNCEND volume_accessibility_matches;
?? OLDTITLE ??
?? OLDTITLE ??
MODEND rmm$enforce_tape_security;
