?? RIGHT := 110 ??
?? TITLE := 'NOS/VE Permanent Files : Get Object Information' ??
MODULE pfm$r2_get_object_information;

{ PURPOSE:
{   This module contains the procedures to get information about a catalog,
{   file, or cycle.

?? NEWTITLE := '  Global Declarations Referenced by this module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc oss$job_paged_literal
*copyc fsc$local
*copyc pfc$average_share_history
*copyc pfc$maximum_pf_length
*copyc pfc$system_shared_queue_name
*copyc osd$integer_limits
*copyc ame$lfn_program_actions
*copyc pfe$error_condition_codes
*copyc pfe$get_object_info_errors
*copyc pfe$internal_error_conditions
*copyc dmt$error_condition_codes
*copyc dmt$stored_ms_fmd_header
*copyc fst$file_access_conditions
*copyc fst$goi_object_information
*copyc fst$goi_validation_criteria
*copyc fst$path_element_name
*copyc gft$system_file_identifier
*copyc pft$p_fmd
*copyc pft$unique_volume_list
?? POP ??
*copyc bap$set_evaluated_file_abnormal
*copyc clp$convert_file_ref_to_string
*copyc dfp$check_self_serving_job
*copyc dfp$locate_served_family
*copyc dmp$attach_file
*copyc dmp$fetch_eoi
*copyc dmp$get_file_info
*copyc dmp$get_server_fmd
*copyc dmp$get_stored_fmd
*copyc dmp$get_stored_fmd_header_info
*copyc dmp$get_stored_fmd_size
*copyc dmp$get_stored_fmd_volume_list
*copyc dmp$get_tape_volume_information
*copyc dmp$get_tape_volume_list
*copyc dmp$get_unique_fmd_volume_list
*copyc fmp$complete_pf_object_info
*copyc fmp$get_$local_object_info
*copyc fmp$get_attached_tape_info
*copyc fmp$get_label_header_info
*copyc fmp$get_path_table_cycle_info
*copyc fmp$get_setfa_values_for_object
*copyc fmp$lock_path_table
*copyc fmp$merge_setfa_entries
*copyc fmp$process_pt_request
*copyc fmp$setup_job_environment_info
*copyc fmp$unlock_path_table
*copyc fsp$path_element
*copyc mmp$create_scratch_segment
*copyc mmp$delete_scratch_segment
*copyc mmp$fetch_segment_attributes
*copyc osp$append_status_parameter
*copyc osp$disestablish_cond_handler
*copyc osp$establish_condition_handler
*copyc osp$file_access_condition
*copyc osp$get_set_name
*copyc osp$recoverable_system_error
*copyc osp$set_status_abnormal
*copyc osp$set_status_condition
*copyc osp$set_status_from_condition
*copyc pfp$access_next_catalog
*copyc pfp$access_object
*copyc pfp$build_amd_pointer
*copyc pfp$build_archive_list_pointer
*copyc pfp$build_cycle_list_pointer
*copyc pfp$build_file_label_pointer
*copyc pfp$build_fmd_pointer
*copyc pfp$build_log_list_pointer
*copyc pfp$build_mainfram_list_pointer
*copyc pfp$build_permit_list_pointer
*copyc pfp$check_archive_entries
*copyc pfp$check_for_stale_cycle_entry
*copyc pfp$compute_checksum
*copyc pfp$convert_device_class_to_rm
*copyc pfp$convert_fs_to_complete_path
*copyc pfp$convert_fs_to_pft$path
*copyc pfp$convert_ord_to_shared_queue
*copyc pfp$cycle_attached_for_write
*copyc pfp$detach_permanent_file
*copyc pfp$extract_permit_entry
*copyc pfp$form_administrator_permit
*copyc pfp$get_authority
*copyc pfp$get_rem_media_req_info
*copyc pfp$get_rem_media_volume_list
*copyc pfp$get_sorted_object_name_list
*copyc pfp$initialize_object_info
*copyc pfp$locate_cycle
*copyc pfp$locate_log_entry
*copyc pfp$log_ascii
*copyc pfp$log_path
*copyc pfp$process_unexpected_status
*copyc pfp$r2_df_client_get_family_set
*copyc pfp$r2_df_client_get_obj_info
*copyc pfp$r2_df_client_get_vol_cl
*copyc pfp$r2_df_client_validate_pw
*copyc pfp$r2_get_stored_fmd
*copyc pfp$r2_get_stored_fmd_size
*copyc pfp$r2_get_vol_condition_list
*copyc pfp$r2_validate_password
*copyc pfp$reconcile_fmd
*copyc pfp$reduce_permits
*copyc pfp$release_locked_apfid
*copyc pfp$report_unexpected_status
*copyc pfp$return_catalog
*copyc pfp$set_status_abnormal
*copyc pfp$shared_queue
*copyc pfp$update_stale_cycle_entry
*copyc pfp$validate_password
*copyc pfp$validate_ring_access
*copyc pmp$compute_local_date_time
*copyc pmp$continue_to_cause
*copyc pmp$get_pseudo_mainframe_id
*copyc pmp$get_time_zone
*copyc pmp$get_user_identification
*copyc syp$pop_inhibit_job_recovery
*copyc syp$push_inhibit_job_recovery
*copyc fmv$static_label_header
*copyc osv$catalog_name_security
*copyc osv$system_family_name
*copyc pfv$locked_apfid
*copyc pfv$null_unique_name
*copyc pfv$unattached_status
*copyc i#move
*copyc pfi$convert_cycle_reference

?? TITLE := '  Global Declarations Declared by this module', EJECT ??

  TYPE
    adaptable_array_ptr_converter = record
      case adaptable_array_ptr_kind of
      = adaptable_array_ptr_data_rep =
        pva: ost$pva,
        array_size: 0 .. 0ffffffff(16),
        lower_bound: 0 .. 0ffffffff(16),
        element_size: 0 .. 0ffffffff(16),
      = archive_information_list_ptr =
        p_archive_information_list: ^fst$archive_information_list,
      = log_array_ptr =
        p_log_array: ^pft$log_array,
      = object_list_ptr =
        p_object_list: ^fst$goi_object_list,
      = permit_array_ptr =
        p_permit_array: ^pft$permit_array,
      = volume_condition_list_ptr =
        p_volume_condition_list: ^fst$volume_condition_list,
      = volume_list_ptr =
        p_volume_list: ^rmt$volume_list,
      casend,
    recend,

    adaptable_array_ptr_kind = (adaptable_array_ptr_data_rep, archive_information_list_ptr, log_array_ptr,
          object_list_ptr, permit_array_ptr, volume_condition_list_ptr, volume_list_ptr),

    adaptable_string_ptr_converter = record
      case adaptable_string_ptr_kind of
      = adaptable_string_ptr_data_rep =
        pva: ost$pva,
        length: 0 .. 0ffff(16),
      = file_reference_ptr =
        p_file_reference: ^fst$file_reference,
      casend,
    recend,

    adaptable_string_ptr_kind = (adaptable_string_ptr_data_rep, file_reference_ptr),

    sequence_ptr_converter = record
      case sequence_ptr_kind of
      = sequence_ptr =
        p_sequence: ^SEQ ( * ),
      = sequence_ptr_data_rep =
        pva: ost$pva,
        length: 0 .. 07fffffff(16),
        nextt: 0 .. 07fffffff(16),
      casend,
    recend,

    sequence_ptr_kind = (sequence_ptr, sequence_ptr_data_rep),

    subject_permit_id_list = array [1 .. * ] of subject_permit_identifier,

    subject_permit_identifier = record
      authority: pft$authority,
      permit_type: pft$permit_type,
      group_type: pft$group_types,
    recend;

  VAR
    pfv$catalog_info_requests: [XDCL, oss$job_paged_literal, READ] fst$goi_object_info_requests :=
          [fsc$goi_catalog_identity, fsc$goi_applicable_cat_permit, fsc$goi_catalog_device_info,
          fsc$goi_catalog_info, fsc$goi_catalog_permits, fsc$goi_catalog_size, fsc$goi_catalog_object_list,
          fsc$goi_file_object_list],
    pfv$cycle_info_requests: [XDCL, oss$job_paged_literal, READ] fst$goi_object_info_requests :=
          [fsc$goi_cycle_identity, fsc$goi_archive_info, fsc$goi_cycle_device_info, fsc$goi_cycle_info,
          fsc$goi_cycle_size, fsc$goi_file_label, fsc$goi_job_environment_info],
    pfv$file_info_requests: [XDCL, oss$job_paged_literal, READ] fst$goi_object_info_requests :=
          [fsc$goi_file_identity, fsc$goi_applicable_file_permit, fsc$goi_file_info, fsc$goi_file_log,
          fsc$goi_file_permits, fsc$goi_cycle_object_list];

  VAR
    object_list_requests: [oss$job_paged_literal, READ] fst$goi_object_info_requests :=
          [fsc$goi_catalog_object_list, fsc$goi_cycle_object_list, fsc$goi_file_object_list],
    protected_info_requests: [oss$job_paged_literal, READ] fst$goi_object_info_requests :=
          [fsc$goi_file_label, fsc$goi_job_environment_info],
    valid_objects: [oss$job_paged_literal, READ] pft$object_selections :=
          [pfc$file_object, pfc$catalog_object];

?? TITLE := '  [XDCL] pfp$get_attached_device_info', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to get the device information about a
{   cycle which is attached within the job.

  PROCEDURE [XDCL] pfp$get_attached_device_info
    (    temporary_file: boolean;
         served_family: boolean;
         served_family_locator: {input^} ^pft$served_family_locator,
         p_cycle_description: {input^} ^fmt$cycle_description;
         p_object: {output^} ^fst$goi_object;
     VAR p_object_information: ^SEQ ( * );
     VAR eoi: amt$file_byte_address;
     VAR status: ost$status);

    VAR
      device_information_initialized: boolean,
      dm_file_information: dmt$file_information,
      fmd_size: dmt$stored_fmd_size,
      p_device_information: ^fst$device_information,
      p_fmd: ^dmt$stored_fmd,
      removable_media_group: ost$name,
      shared_queue: pft$shared_queue,
      shared_queue_name: ost$name,
      volume_number: amt$volume_number;

    NEXT p_device_information IN p_object_information;
    IF p_device_information = NIL THEN
      osp$set_status_condition (pfe$info_full, status);
      RETURN;
    IFEND;

    IF temporary_file AND (p_cycle_description^.device_class = rmc$magnetic_tape_device) THEN
      fmp$get_attached_tape_info (p_cycle_description^.system_file_id, p_device_information^.
            magnetic_tape_device_info.volume_list, volume_number, p_device_information^.
            magnetic_tape_device_info.volume_overflow_allowed, p_device_information^.
            magnetic_tape_device_info.density, removable_media_group, p_object_information, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      p_object^.cycle_device_information := p_device_information;
    ELSEIF p_cycle_description^.device_class = rmc$mass_storage_device THEN
      fmd_size := #SIZE (dmt$stored_ms_fmd_header) + (4 * #SIZE (dmt$stored_ms_fmd_subfile));
      IF served_family THEN
        REPEAT
          PUSH p_fmd: [[REP fmd_size OF cell]];
          dmp$get_server_fmd (p_cycle_description^.system_file_id, p_fmd^, fmd_size, status);
        UNTIL status.normal OR (status.condition <> dme$fmd_too_small);
      ELSE
        PUSH p_fmd: [[REP fmd_size OF cell]];
        dmp$get_stored_fmd (p_cycle_description^.system_file_id, p_fmd^, status);

        IF (NOT status.normal) AND (status.condition = dme$fmd_too_small) THEN
          dmp$get_stored_fmd_size (p_cycle_description^.system_file_id, fmd_size, status);
          IF NOT status.normal THEN
            RETURN;
          IFEND;

          PUSH p_fmd: [[REP fmd_size OF cell]];
          dmp$get_stored_fmd (p_cycle_description^.system_file_id, p_fmd^, status);
        IFEND;
      IFEND;
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      dmp$get_file_info (p_cycle_description^.system_file_id, dm_file_information, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      p_device_information^.mass_storage_device_info.bytes_allocated :=
            dm_file_information.total_allocated_length;

      IF temporary_file THEN
        p_device_information^.mass_storage_device_info.shared_queue := osc$null_name;
      ELSE
        pfp$convert_ord_to_shared_queue (dm_file_information.shared_queue, shared_queue_name, status);
        IF status.normal THEN
          p_device_information^.mass_storage_device_info.shared_queue := shared_queue_name;
        ELSE
          p_device_information^.mass_storage_device_info.shared_queue := pfc$system_shared_queue_name;
          status.normal := TRUE;
        IFEND;
      IFEND;

      get_disk_device_info_from_fmd (p_fmd, p_device_information, device_information_initialized,
            p_object_information, status);
      IF device_information_initialized THEN
        IF status.normal THEN
          get_object_condition ({catalog_object} FALSE, served_family, served_family_locator, p_fmd,
                p_device_information^.mass_storage_device_info,  p_object_information, status);
        IFEND;
        IF status.normal THEN
          p_object^.cycle_device_information := p_device_information;
        IFEND;
      IFEND;
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      eoi := dm_file_information.eoi_byte_address;
    IFEND;
  PROCEND pfp$get_attached_device_info;

?? TITLE := '  [XDCL] pfp$r2_get_object_info', EJECT ??

{ PURPOSE:
{   This purpose of this procedure is to get subject permit information, the
{   set name, and the resolved path for the specified object.

  PROCEDURE [XDCL] pfp$r2_get_object_info
    (    family_location: pft$family_location;
         binary_mainframe_id: pmt$binary_mainframe_id;
         evaluated_file_reference: fst$evaluated_file_reference;
         information_request: fst$goi_information_request;
         system_privilege: boolean;
         password_selector: pft$password_selector;
         subject_permit_count: ost$non_negative_integers;
         validation_ring: ost$valid_ring;
         p_validation_criteria: {i^/o^} ^fst$goi_validation_criteria;
         p_object_info: {output^} ^fst$goi_object_information;
     VAR p_object_information: ^SEQ ( * );
     VAR status: ost$status);

    PROCEDURE get_object_info_handler
      (    condition: pmt$condition;
           p_condition_info: ^pmt$condition_information;
           p_sfsa: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      VAR
        local_status: ost$status,
        status_id: ost$status_identifier,
        variant_path: pft$variant_path;

      variant_path.complete_path := TRUE;
      variant_path.p_complete_path := p_path;

      IF NOT process_non_local_exit THEN
        pfp$log_ascii ('***PF Condition Handler***', $pmt$ascii_logset [pmc$system_log, pmc$job_log],
              pmc$msg_origin_system, {critical_message} FALSE, local_status);
        pfp$log_path (variant_path, $pmt$ascii_logset [pmc$system_log, pmc$job_log], pmc$msg_origin_system,
              {critical_message} FALSE, local_status);
      IFEND;

      CASE condition.selector OF
      = pmc$system_conditions, pmc$block_exit_processing, mmc$segment_access_condition =
        IF process_non_local_exit THEN
          RETURN;
        IFEND;

        IF catalog_locator.attached THEN
          catalog_locator.abort_catalog_operation := TRUE;
          pfp$return_catalog (catalog_locator, local_status);
          IF NOT local_status.normal THEN
            pfp$report_system_error (local_status);
          IFEND;
        IFEND;

        osp$set_status_from_condition (status_id, condition, p_sfsa, local_status, handler_status);
        osp$recoverable_system_error ('UNEXPECTED STATUS', ^local_status);

        osp$set_status_abnormal (pfc$permanent_file_manager_id, pfe$pf_system_error,
              'PFP$R2_GET_OBJECT_INFO failure - see job log for details.', status);
        process_non_local_exit := TRUE;
        #SPOIL(process_non_local_exit);
        EXIT pfp$r2_get_object_info;

      = pmc$user_defined_condition =
        IF condition.user_condition_name = 'OSC$JOB_RECOVERY' THEN
          process_non_local_exit := TRUE;
          #SPOIL(process_non_local_exit);
          EXIT pfp$r2_get_object_info;
        ELSE
          pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);
        IFEND;
      ELSE
        pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);
      CASEND;

    PROCEND get_object_info_handler;

    VAR
      authority: pft$authority,
      catalog_locator: pft$catalog_locator,
      cycle_selector: pft$cycle_selector,
      local_authority: pft$authority,
      local_evaluated_file_reference: fst$evaluated_file_reference,
      local_status: ost$status,
      object_information_requests: fst$goi_object_info_requests,
      p_complete_path: ^pft$complete_path,
      p_cycle_list: ^pft$cycle_list,
      p_internal_path: ^pft$internal_path,
      p_path: ^pft$path,
      p_physical_cycle: ^pft$physical_cycle,
      p_physical_object: ^pft$physical_object,
      p_subject_permit_id_list: ^subject_permit_id_list,
      parent_charge_id: pft$charge_id,
      permit_entry: pft$permit_entry,
      permitted_to_object: boolean,
      process_non_local_exit: boolean,
      unknown_cycle: boolean,
      variant_path: pft$variant_path;

    process_non_local_exit := FALSE;
    #SPOIL(process_non_local_exit);

    PUSH p_complete_path: [1 .. evaluated_file_reference.number_of_path_elements + 1];
    pfp$convert_fs_to_complete_path (evaluated_file_reference, p_complete_path, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    pfp$get_authority (p_complete_path^, system_privilege, authority, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF subject_permit_count = 0 THEN
      p_subject_permit_id_list := NIL;
    ELSE
      IF authority.ownership = $pft$ownership [] THEN
        osp$set_status_condition (pfe$neither_owner_nor_admin, status);
        RETURN;
      IFEND;

      PUSH p_subject_permit_id_list: [1 .. subject_permit_count];
      resolve_subject_permits (p_complete_path^, authority, p_validation_criteria, p_subject_permit_id_list,
            status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
    IFEND;

    local_authority := authority;
    local_authority.ownership := $pft$ownership [pfc$system_owner];

    object_information_requests := information_request.object_information_requests;

    PUSH p_internal_path: [1 .. evaluated_file_reference.number_of_path_elements + 1];
    IF object_information_requests *
          $fst$goi_object_info_requests [fsc$goi_cycle_device_info, fsc$goi_cycle_size] <>
          $fst$goi_object_info_requests [] THEN
      {
      { A cycle's fmd may need to be reconciled, so the catalog must be
      { attached for write.
      {
      pfp$access_object (p_complete_path^, pfc$write_access, local_authority, valid_objects, parent_charge_id,
            catalog_locator, p_physical_object, p_internal_path^, permit_entry, status);
    ELSE
      pfp$access_object (p_complete_path^, pfc$read_access, local_authority, valid_objects, parent_charge_id,
            catalog_locator, p_physical_object, p_internal_path^, permit_entry, status);
    IFEND;

    IF NOT status.normal THEN
      IF (status.condition = pfe$unknown_item) AND (authority.ownership = $pft$ownership []) AND
            ((permit_entry.entry_type = pfc$free_permit_entry) OR
            NOT (pfc$cycle IN permit_entry.usage_permissions)) THEN
        variant_path.complete_path := TRUE;
        variant_path.p_complete_path := p_complete_path;
        pfp$set_status_abnormal (variant_path, pfe$unknown_permanent_file, status);
      IFEND;
      RETURN;
    IFEND;

    PUSH p_path: [1 .. evaluated_file_reference.number_of_path_elements];
    pfp$convert_fs_to_pft$path (evaluated_file_reference, p_path^);
    osp$establish_condition_handler (^get_object_info_handler, {block_exit} TRUE);

  /catalog_attached/
    BEGIN
      pfp$form_administrator_permit (authority, permit_entry);
      permitted_to_object := (authority.ownership <> $pft$ownership []) OR
            ((permit_entry.entry_type = pfc$normal_permit_entry) AND
            (permit_entry.usage_permissions <> $pft$permit_selections []));

      IF fsc$goi_set_name IN object_information_requests THEN
        p_object_info^.set_name := p_complete_path^ [pfc$set_path_index];
      IFEND;

    /resolve_path/
      BEGIN
        local_evaluated_file_reference := evaluated_file_reference;
        IF (p_physical_object^.object_entry.object_type = pfc$catalog_object) OR
              (fsc$goi_cycle_object_list IN object_information_requests) OR
              (object_information_requests * pfv$cycle_info_requests = $fst$goi_object_info_requests []) THEN
          local_evaluated_file_reference.cycle_reference.specification := fsc$cycle_omitted;
          unknown_cycle := FALSE; { The cycle is omitted, not unknown.
          p_physical_cycle := NIL;
        ELSEIF evaluated_file_reference.cycle_reference.specification = fsc$next_cycle THEN
          unknown_cycle := TRUE;
          p_physical_cycle := NIL;
          variant_path.complete_path := TRUE;
          variant_path.p_complete_path := p_complete_path;
          pfp$set_status_abnormal (variant_path, pfe$unknown_cycle, status);
          osp$append_status_parameter (osc$status_parameter_delimiter, '$NEXT', status);
          EXIT /resolve_path/;
        ELSE
          pfp$build_cycle_list_pointer (p_physical_object^.object_entry.cycle_list_locator,
                catalog_locator.p_catalog_file, p_cycle_list);
          pfi$convert_cycle_reference (evaluated_file_reference.cycle_reference, cycle_selector, status);
          IF NOT status.normal THEN
            unknown_cycle := TRUE;
            p_physical_cycle := NIL;
            EXIT /resolve_path/;
          IFEND;

          pfp$locate_cycle (p_complete_path^, p_cycle_list, cycle_selector, p_physical_cycle, status);
          IF NOT status.normal THEN
            unknown_cycle := TRUE;
            EXIT /resolve_path/;
          IFEND;

          local_evaluated_file_reference.cycle_reference.specification := fsc$cycle_number;
          local_evaluated_file_reference.cycle_reference.cycle_number :=
                p_physical_cycle^.cycle_entry.cycle_number;
          unknown_cycle := FALSE;
        IFEND;

        store_resolved_path (local_evaluated_file_reference, p_object_info, p_object_information, status);
        IF (NOT status.normal) AND (status.condition = pfe$info_full) THEN
          EXIT /catalog_attached/;
        IFEND;
      END /resolve_path/;

      IF ((p_physical_object^.object_entry.object_type = pfc$file_object) AND
            (object_information_requests - pfv$catalog_info_requests <> $fst$goi_object_info_requests [])) OR
            ((p_physical_object^.object_entry.object_type = pfc$catalog_object) AND
            ((object_information_requests * pfv$catalog_info_requests <> $fst$goi_object_info_requests []) OR
            NOT permitted_to_object)) THEN
        get_object_information (family_location, binary_mainframe_id, p_complete_path^, information_request,
              authority, permit_entry, p_physical_object, unknown_cycle, password_selector, validation_ring,
              p_subject_permit_id_list, p_physical_cycle, p_object_info, catalog_locator, permitted_to_object,
              p_object_information, local_status);

        IF (NOT local_status.normal) AND (status.normal OR (local_status.condition = pfe$info_full)) THEN
          status := local_status;
        ELSEIF NOT permitted_to_object THEN
          variant_path.complete_path := TRUE;
          variant_path.p_complete_path := p_complete_path;
          pfp$set_status_abnormal (variant_path, pfe$unknown_item, status);
        IFEND;
      IFEND;
    END /catalog_attached/;

    osp$disestablish_cond_handler;
    pfp$return_catalog (catalog_locator, local_status);
    pfp$process_unexpected_status (local_status);
  PROCEND pfp$r2_get_object_info;

?? TITLE := '  [XDCL, #GATE] pfp$r2_get_object_information', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to get the requested information about the
{   specified catalog, file, or cycle.

  PROCEDURE [XDCL, #GATE] pfp$r2_get_object_information
    (    evaluated_file_reference: fst$evaluated_file_reference;
         information_request: fst$goi_information_request;
         system_privilege: boolean;
         password_selector: pft$password_selector;
         subject_permit_count: ost$non_negative_integers;
         validation_ring: ost$valid_ring;
         p_validation_criteria: {i^/o^} ^fst$goi_validation_criteria;
     VAR p_object_information: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      all_protected_info_returned: boolean,
      binary_mainframe_id: pmt$binary_mainframe_id,
      check_path_table_for_setfa: boolean,
      first_path_element_name: fst$path_element_name,
      local_evaluated_file_reference: fst$evaluated_file_reference,
      local_status: ost$status,
      object_info_offset: ost$segment_offset,
      p_cycle_description: ^fmt$cycle_description,
      p_local_object_information: ^SEQ ( * ),
      p_object_info: ^fst$goi_object_information,
      process_pt_results: bat$process_pt_results,
      scratch_segment_created: boolean,
      scratch_segment_pointer: amt$segment_pointer,
      segment_attributes: array [1 .. 1] of mmt$attribute_descriptor,
      served_family: boolean,
      served_family_locator: pft$served_family_locator,
      setfa_found: boolean,
      using_local_object_info_seq: boolean;

    first_path_element_name := fsp$path_element (^evaluated_file_reference, 1)^;

    IF #SIZE (p_object_information^) <= 2000000 THEN
      PUSH p_local_object_information: [[REP #SIZE (p_object_information^) OF cell,
            REP #SIZE (p_object_information^) DIV #SIZE (fst$goi_object) OF pft$password]];
      RESET p_local_object_information;
      using_local_object_info_seq := TRUE;
      scratch_segment_created := FALSE;
    ELSE
      IF first_path_element_name = fsc$local THEN
        served_family := FALSE;
      ELSE
        find_family_location (first_path_element_name, served_family, served_family_locator);
      IFEND;

      IF NOT served_family THEN
        segment_attributes [1].keyword := mmc$kw_ring_numbers;
        mmp$fetch_segment_attributes (p_object_information, segment_attributes, status);
      IFEND;

      IF status.normal AND (NOT served_family) AND (segment_attributes [1].r2 <= osc$tsrv_ring) THEN
        p_local_object_information := p_object_information;
        using_local_object_info_seq := FALSE;
      ELSE
        mmp$create_scratch_segment (amc$sequence_pointer, mmc$as_sequential, scratch_segment_pointer, status);
        IF status.normal THEN
          using_local_object_info_seq := TRUE;
          scratch_segment_created := TRUE;
          p_local_object_information := scratch_segment_pointer.sequence_pointer;
          RESET p_local_object_information;
        ELSE
          RETURN;
        IFEND;
      IFEND;
    IFEND;

  /get_information/
    BEGIN;
      NEXT p_object_info IN p_local_object_information;
      IF p_object_info = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        EXIT /get_information/;
      ELSE
        pfp$initialize_object_info (p_object_info);
      IFEND;

      IF first_path_element_name = fsc$local THEN
        IF subject_permit_count > 0 THEN
          check_subject_permits (evaluated_file_reference, p_validation_criteria, status);
          IF NOT status.normal THEN
            EXIT /get_information/;
          IFEND;
        IFEND;

        fmp$get_$local_object_info (evaluated_file_reference, information_request, password_selector,
              validation_ring, p_object_info, p_local_object_information, status);
        EXIT /get_information/;
      ELSEIF (evaluated_file_reference.cycle_reference.specification = fsc$cycle_number) AND
            (information_request.object_information_requests <= $fst$goi_object_info_requests
            [fsc$goi_set_name, fsc$goi_cycle_identity, fsc$goi_cycle_device_info, fsc$goi_cycle_size,
            fsc$goi_file_label, fsc$goi_job_environment_info]) AND (subject_permit_count = 0) THEN
        local_evaluated_file_reference := evaluated_file_reference;

        fmp$lock_path_table (status);
        IF NOT status.normal THEN
          EXIT /get_information/;
        IFEND;
        fmp$process_pt_request
              ($bat$process_pt_work_list [bac$inhibit_locking_pt, bac$return_cycle_description],
              {local_file_name} osc$null_name, local_evaluated_file_reference, p_cycle_description,
              process_pt_results, status);

        IF status.normal THEN
          IF p_cycle_description = NIL THEN
            check_path_table_for_setfa := FALSE;
          ELSEIF p_cycle_description^.attached_file AND (p_cycle_description^.device_class =
                rmc$mass_storage_device) THEN
            get_attached_cycle_information (evaluated_file_reference, information_request,
                  p_cycle_description, password_selector, validation_ring, p_object_info,
                  p_local_object_information, status);
            fmp$unlock_path_table;
            EXIT /get_information/;
          ELSE
            check_path_table_for_setfa := TRUE;
          IFEND;
        ELSE
          check_path_table_for_setfa := TRUE;
        IFEND;

        fmp$unlock_path_table;
      ELSE
        check_path_table_for_setfa := TRUE;
      IFEND;

      syp$push_inhibit_job_recovery;

      IF using_local_object_info_seq AND NOT scratch_segment_created THEN
        find_family_location (first_path_element_name, served_family, served_family_locator);
      IFEND;

      IF served_family THEN
        pfp$r2_df_client_get_obj_info (served_family_locator, evaluated_file_reference, information_request,
              system_privilege, password_selector, subject_permit_count, validation_ring,
              p_validation_criteria, p_object_info, object_info_offset, p_local_object_information, status);
        {
        { Convert all server pvas to client pvas.
        {
        IF status.normal OR
              ((status.condition <> pfe$pf_system_error) AND (status.condition <> pfe$catalog_access_retry))
              AND (object_info_offset > 0) THEN
          convert_object_info_pointers (object_info_offset, p_object_info, p_local_object_information,
                local_status);
          IF NOT local_status.normal THEN
            status := local_status;
          IFEND;
        IFEND;
      ELSE
        pmp$get_pseudo_mainframe_id (binary_mainframe_id);
        pfp$r2_get_object_info (pfc$local_mainframe, binary_mainframe_id, evaluated_file_reference,
              information_request, system_privilege, password_selector, subject_permit_count,
              validation_ring, p_validation_criteria, p_object_info, p_local_object_information, status);
      IFEND;

      syp$pop_inhibit_job_recovery;

      IF information_request.object_information_requests * $fst$goi_object_info_requests [fsc$goi_cycle_size,
            fsc$goi_file_label, fsc$goi_job_environment_info] <> $fst$goi_object_info_requests [] THEN
        IF NOT status.normal THEN
          IF ((status.condition = pfe$unknown_item) OR (status.condition = pfe$unknown_cycle)) AND
                check_path_table_for_setfa THEN
            {
            { The path table must be checked for setfa values.
            {
            NEXT p_object_info^.object IN p_local_object_information;
            IF p_object_info^.object = NIL THEN
              osp$set_status_condition (pfe$info_full, status);
              EXIT /get_information/;
            IFEND;

            fmp$get_setfa_values_for_object (evaluated_file_reference, information_request, validation_ring,
                  p_object_info^.object, p_local_object_information, setfa_found, local_status);
            IF setfa_found THEN
              store_resolved_path (evaluated_file_reference, p_object_info, p_local_object_information,
                    status);
            ELSE
              p_object_info^.object := NIL;
              IF NOT local_status.normal THEN
                status := local_status;
              IFEND;
            IFEND;

            EXIT /get_information/;
          ELSEIF (status.condition = pfe$info_full) OR (status.condition = pfe$pf_system_error) OR
                (status.condition = pfe$catalog_access_retry) THEN
            EXIT /get_information/;
          IFEND;
        IFEND;

        fmp$complete_pf_object_info (evaluated_file_reference, information_request, password_selector,
              validation_ring, p_object_info^.object, p_local_object_information, all_protected_info_returned,
              local_status);
        status.normal := status.normal OR
              ((status.condition = pfe$incorrect_password) AND all_protected_info_returned);
        IF (NOT local_status.normal) AND (status.normal OR (local_status.condition = pfe$info_full)) THEN
          status := local_status;
        IFEND;
      IFEND;
    END /get_information/;

    IF using_local_object_info_seq THEN
      IF status.normal OR
            ((status.condition <> pfe$pf_system_error) AND (status.condition <> pfe$catalog_access_retry)
            AND (p_object_info <> NIL)) THEN
        move_object_information (p_object_info, p_object_information, local_status);
        IF NOT local_status.normal THEN
          status := local_status;
        IFEND;
      IFEND;

      IF scratch_segment_created THEN
        mmp$delete_scratch_segment (scratch_segment_pointer, local_status);
      IFEND;
    ELSE
      p_object_information := p_local_object_information;
    IFEND;
  PROCEND pfp$r2_get_object_information;

?? TITLE := '  attach_next_catalog', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to retrieve the next catalog in the path
{   from device management.

  PROCEDURE attach_next_catalog
    (    path: pft$complete_path;
         object_information_requests: fst$goi_object_info_requests;
         p_physical_object: {input^} ^pft$physical_object;
     VAR catalog_locator: {i/o} pft$catalog_locator;
     VAR status: ost$status);

    VAR
      local_status: ost$status,
      new_catalog_locator: pft$catalog_locator;

    IF (fsc$goi_cycle_object_list IN object_information_requests) AND
          ($fst$goi_object_info_requests [fsc$goi_cycle_device_info, fsc$goi_cycle_size] *
          object_information_requests <> $fst$goi_object_info_requests []) THEN
      {
      { A cycle's fmd may need to be reconciled, so the catalog must be
      { attached for write.
      {
      pfp$access_next_catalog (pfc$write_access, catalog_locator, p_physical_object,
            ({catalog_remote} path [pfc$family_path_index] <> osv$system_family_name), new_catalog_locator,
            status);
    ELSE
      pfp$access_next_catalog (pfc$read_access, catalog_locator, p_physical_object,
            ({catalog_remote} path [pfc$family_path_index] <> osv$system_family_name), new_catalog_locator,
            status);
    IFEND;
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF new_catalog_locator.internal_catalog_name <> catalog_locator.internal_catalog_name THEN
      pfp$return_catalog (catalog_locator, local_status);
      pfp$process_unexpected_status (local_status);
    IFEND;
    catalog_locator := new_catalog_locator;
  PROCEND attach_next_catalog;

?? TITLE := '  check_subject_permits', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to determine if any subject permits
{   identify someone other than the caller; if so, then an abnormal status is
{   returned.
{
{ NOTE:
{   This procedure should only be used when the caller is neither the owner nor
{   an administrator of the object and the object is a $local catalog, file, or
{   cycle.

  PROCEDURE check_subject_permits
    (    evaluated_file_reference: fst$evaluated_file_reference;
         p_validation_criteria: {i^/o^} ^fst$goi_validation_criteria;
     VAR status: ost$status);

    VAR
      criterion_index: ost$positive_integers,
      p_subject_permit: ^pft$permit_array_entry,
      user_id: ost$user_identification;

    pmp$get_user_identification (user_id, status);

    IF status.normal THEN
      FOR criterion_index := 1 TO UPPERBOUND (p_validation_criteria^) DO
        IF p_validation_criteria^ [criterion_index].validation_selection = fsc$goi_subject_permit THEN
          p_subject_permit := ^p_validation_criteria^ [criterion_index].subject_permit;

          IF ((p_subject_permit^.group.group_type = pfc$family) AND
                (p_subject_permit^.group.user_description.family = user_id.family)) OR
                ((p_subject_permit^.group.group_type = pfc$account) AND
                (p_subject_permit^.group.user_description.family = user_id.family)) OR
                ((p_subject_permit^.group.group_type = pfc$project) AND
                (p_subject_permit^.group.user_description.family = user_id.family)) OR
                ((p_subject_permit^.group.group_type = pfc$user) AND
                (p_subject_permit^.group.user_description.family = user_id.family) AND
                (p_subject_permit^.group.user_description.user = user_id.user)) OR
                ((p_subject_permit^.group.group_type = pfc$user_account) AND
                (p_subject_permit^.group.user_account_description.family = user_id.family) AND
                (p_subject_permit^.group.user_account_description.user = user_id.user)) OR
                ((p_subject_permit^.group.group_type = pfc$member) AND
                (p_subject_permit^.group.member_description.family = user_id.family) AND
                (p_subject_permit^.group.member_description.user = user_id.user)) THEN
            p_subject_permit^.usage_permissions := -$pft$permit_selections [];
            p_subject_permit^.share_requirements := $pft$share_requirements [];
            p_subject_permit^.application_info := osc$null_name;
          ELSE
            p_subject_permit^.usage_permissions := $pft$permit_selections [];
            p_subject_permit^.share_requirements := -$pft$share_selections [];
            p_subject_permit^.application_info := osc$null_name;
            bap$set_evaluated_file_abnormal (evaluated_file_reference, ame$file_not_known,
                  'pfp$get_object_information', '', status);
            RETURN;
          IFEND;
        IFEND;
      FOREND;
    IFEND;
  PROCEND check_subject_permits;

?? TITLE := '  convert_catalog_object_pointers', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to convert pvas, within a catalog object
{   of the object information sequence, which are valid on the server to pvas
{   which are valid on the client.

  PROCEDURE convert_catalog_object_pointers
    (    object_info_offset_difference: ost$segment_offset;
         p_object: {i^/o^} ^fst$goi_object;
     VAR p_object_information: {i/o} ^SEQ ( * );
     VAR status: ost$status);

    VAR
      adaptable_array_ptr_convtr: adaptable_array_ptr_converter,
      object_index: ost$positive_integers,
      p_device_information: ^fst$device_information,
      p_object_list: ^fst$goi_object_list,
      ring: ost$valid_ring,
      segment: ost$segment;

    ring := #RING (p_object_information);
    segment := #SEGMENT (p_object_information);

    IF p_object^.applicable_catalog_permit <> NIL THEN
      p_object^.applicable_catalog_permit := #ADDRESS (ring, segment,
            #OFFSET (p_object^.applicable_catalog_permit) - object_info_offset_difference);
    IFEND;

    IF p_object^.catalog_device_information <> NIL THEN
      p_object^.catalog_device_information := #ADDRESS (ring, segment,
            #OFFSET (p_object^.catalog_device_information) - object_info_offset_difference);

      RESET p_object_information TO p_object^.catalog_device_information;
      NEXT p_device_information IN p_object_information;
      IF p_device_information = NIL THEN
        osp$set_status_abnormal (pfc$permanent_file_manager_id, pfe$pf_system_error,
              'p_device_information = NIL  convert_catalog_object_pointers', status);
        RETURN;
      IFEND;

      IF p_device_information^.mass_storage_device_info.volume_list <> NIL THEN
        adaptable_array_ptr_convtr.p_volume_list :=
              p_device_information^.mass_storage_device_info.volume_list;
        adaptable_array_ptr_convtr.pva.ring := ring;
        adaptable_array_ptr_convtr.pva.seg := segment;
        adaptable_array_ptr_convtr.pva.offset :=
              #OFFSET (p_device_information^.mass_storage_device_info.volume_list) -
              object_info_offset_difference;
        p_device_information^.mass_storage_device_info.volume_list :=
              adaptable_array_ptr_convtr.p_volume_list;
      IFEND;

      IF p_device_information^.mass_storage_device_info.volume_condition_list <> NIL THEN
        adaptable_array_ptr_convtr.p_volume_condition_list :=
              p_device_information^.mass_storage_device_info.volume_condition_list;
        adaptable_array_ptr_convtr.pva.ring := ring;
        adaptable_array_ptr_convtr.pva.seg := segment;
        adaptable_array_ptr_convtr.pva.offset :=
              #OFFSET (p_device_information^.mass_storage_device_info.volume_condition_list) -
              object_info_offset_difference;
        p_device_information^.mass_storage_device_info.volume_condition_list :=
              adaptable_array_ptr_convtr.p_volume_condition_list;
      IFEND;
    IFEND;

    IF p_object^.catalog_information <> NIL THEN
      p_object^.catalog_information := #ADDRESS (ring, segment,
            #OFFSET (p_object^.catalog_information) - object_info_offset_difference);
    IFEND;

    IF p_object^.catalog_permits <> NIL THEN
      adaptable_array_ptr_convtr.p_permit_array := p_object^.catalog_permits;
      adaptable_array_ptr_convtr.pva.ring := ring;
      adaptable_array_ptr_convtr.pva.seg := segment;
      adaptable_array_ptr_convtr.pva.offset :=
            #OFFSET (p_object^.catalog_permits) - object_info_offset_difference;
      p_object^.catalog_permits := adaptable_array_ptr_convtr.p_permit_array;
    IFEND;

    IF p_object^.catalog_size <> NIL THEN
      p_object^.catalog_size := #ADDRESS (ring, segment,
            #OFFSET (p_object^.catalog_size) - object_info_offset_difference);
    IFEND;

    IF p_object^.subcatalog_and_file_object_list <> NIL THEN
      adaptable_array_ptr_convtr.p_object_list := p_object^.subcatalog_and_file_object_list;
      adaptable_array_ptr_convtr.pva.ring := ring;
      adaptable_array_ptr_convtr.pva.seg := segment;
      adaptable_array_ptr_convtr.pva.offset :=
            #OFFSET (p_object^.subcatalog_and_file_object_list) - object_info_offset_difference;
      p_object^.subcatalog_and_file_object_list := adaptable_array_ptr_convtr.p_object_list;

      RESET p_object_information TO p_object^.subcatalog_and_file_object_list;
      NEXT p_object_list: [1 .. UPPERBOUND (p_object^.subcatalog_and_file_object_list^)]
            IN p_object_information;
      IF p_object_list = NIL THEN
        osp$set_status_abnormal (pfc$permanent_file_manager_id, pfe$pf_system_error,
              'p_object_list = NIL  convert_catalog_object_pointers', status);
        RETURN;
      IFEND;

      FOR object_index := 1 TO UPPERBOUND (p_object_list^) DO
        CASE p_object_list^ [object_index].object_type OF
        = fsc$goi_catalog_object =
          convert_catalog_object_pointers (object_info_offset_difference, ^p_object_list^ [object_index],
                p_object_information, status);
        = fsc$goi_file_object =
          convert_file_object_pointers (object_info_offset_difference, ^p_object_list^ [object_index],
                p_object_information, status);
        ELSE
          osp$set_status_abnormal (pfc$permanent_file_manager_id, pfe$pf_system_error,
                'Invalid object_type in subcatalog_and_file_object_list.  convert_catalog_object_pointers',
                status);
        CASEND;
        IF NOT status.normal THEN
          RETURN;
        IFEND;
      FOREND;
    IFEND;

    status.normal := TRUE;
  PROCEND convert_catalog_object_pointers;

?? TITLE := '  convert_cycle_object_pointers', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to convert pvas, within a cycle object of
{   the object information sequence, which are valid on the server to pvas
{   which are valid on the client.

  PROCEDURE convert_cycle_object_pointers
    (    object_info_offset_difference: ost$segment_offset;
         p_object: {i^/o^} ^fst$goi_object;
     VAR p_object_information: {i/o} ^SEQ ( * );
     VAR status: ost$status);

    VAR
      adaptable_array_ptr_convtr: adaptable_array_ptr_converter,
      archive_index: ost$positive_integers,
      object_index: ost$positive_integers,
      p_archive_information_list: ^fst$archive_information_list,
      p_device_information: ^fst$device_information,
      ring: ost$valid_ring,
      segment: ost$segment,
      sequence_ptr_convtr: sequence_ptr_converter;

    ring := #RING (p_object_information);
    segment := #SEGMENT (p_object_information);

    IF p_object^.archive_information_list <> NIL THEN
      adaptable_array_ptr_convtr.p_archive_information_list := p_object^.archive_information_list;
      adaptable_array_ptr_convtr.pva.ring := ring;
      adaptable_array_ptr_convtr.pva.seg := segment;
      adaptable_array_ptr_convtr.pva.offset :=
            #OFFSET (p_object^.archive_information_list) - object_info_offset_difference;
      p_object^.archive_information_list := adaptable_array_ptr_convtr.p_archive_information_list;

      RESET p_object_information TO p_object^.archive_information_list;
      NEXT p_archive_information_list: [1 .. UPPERBOUND (p_object^.archive_information_list^)]
            IN p_object_information;
      IF p_archive_information_list = NIL THEN
        osp$set_status_abnormal (pfc$permanent_file_manager_id, pfe$pf_system_error,
              'p_archive_information_list = NIL  convert_cycle_object_pointers', status);
        RETURN;
      IFEND;

      FOR archive_index := 1 TO UPPERBOUND (p_object^.archive_information_list^) DO
        IF p_archive_information_list^ [archive_index].amd <> NIL THEN
          sequence_ptr_convtr.p_sequence := p_archive_information_list^ [archive_index].amd;
          sequence_ptr_convtr.pva.ring := ring;
          sequence_ptr_convtr.pva.seg := segment;
          sequence_ptr_convtr.pva.offset :=
                #OFFSET (p_archive_information_list^ [archive_index].amd) - object_info_offset_difference;
          p_archive_information_list^ [archive_index].amd := sequence_ptr_convtr.p_sequence;
        IFEND;
      FOREND;
    IFEND;

    IF p_object^.cycle_device_information <> NIL THEN
      p_object^.cycle_device_information := #ADDRESS (ring, segment,
            #OFFSET (p_object^.cycle_device_information) - object_info_offset_difference);

      RESET p_object_information TO p_object^.cycle_device_information;
      NEXT p_device_information IN p_object_information;
      IF p_device_information = NIL THEN
        osp$set_status_abnormal (pfc$permanent_file_manager_id, pfe$pf_system_error,
              'p_device_information = NIL  convert_cycle_object_pointers', status);
        RETURN;
      IFEND;

      IF (p_object^.cycle_device_class = rmc$mass_storage_device) AND p_device_information^.
            mass_storage_device_info.resides_online THEN
        IF p_device_information^.mass_storage_device_info.volume_list <> NIL THEN
          adaptable_array_ptr_convtr.p_volume_list :=
                p_device_information^.mass_storage_device_info.volume_list;
          adaptable_array_ptr_convtr.pva.ring := ring;
          adaptable_array_ptr_convtr.pva.seg := segment;
          adaptable_array_ptr_convtr.pva.offset :=
                #OFFSET (p_device_information^.mass_storage_device_info.volume_list) -
                object_info_offset_difference;
          p_device_information^.mass_storage_device_info.volume_list :=
                adaptable_array_ptr_convtr.p_volume_list;
        IFEND;
        IF p_device_information^.mass_storage_device_info.volume_condition_list <> NIL THEN
          adaptable_array_ptr_convtr.p_volume_condition_list :=
                p_device_information^.mass_storage_device_info.volume_condition_list;
          adaptable_array_ptr_convtr.pva.ring := ring;
          adaptable_array_ptr_convtr.pva.seg := segment;
          adaptable_array_ptr_convtr.pva.offset :=
                #OFFSET (p_device_information^.mass_storage_device_info.volume_condition_list) -
                object_info_offset_difference;
          p_device_information^.mass_storage_device_info.volume_condition_list :=
                adaptable_array_ptr_convtr.p_volume_condition_list;
        IFEND;
      ELSEIF p_object^.cycle_device_class = rmc$magnetic_tape_device THEN
        IF p_device_information^.magnetic_tape_device_info.volume_list <> NIL THEN
          adaptable_array_ptr_convtr.p_volume_list :=
                p_device_information^.magnetic_tape_device_info.volume_list;
          adaptable_array_ptr_convtr.pva.ring := ring;
          adaptable_array_ptr_convtr.pva.seg := segment;
          adaptable_array_ptr_convtr.pva.offset :=
                #OFFSET (p_device_information^.magnetic_tape_device_info.volume_list) -
                object_info_offset_difference;
          p_device_information^.magnetic_tape_device_info.volume_list :=
                adaptable_array_ptr_convtr.p_volume_list;
        IFEND;
      IFEND;
    IFEND;

    IF p_object^.cycle_information <> NIL THEN
      p_object^.cycle_information := #ADDRESS (ring, segment,
            #OFFSET (p_object^.cycle_information) - object_info_offset_difference);
    IFEND;

    IF p_object^.cycle_size <> NIL THEN
      p_object^.cycle_size := #ADDRESS (ring, segment,
            #OFFSET (p_object^.cycle_size) - object_info_offset_difference);
    IFEND;

    IF p_object^.file_label <> NIL THEN
      sequence_ptr_convtr.p_sequence := p_object^.file_label;
      sequence_ptr_convtr.pva.ring := ring;
      sequence_ptr_convtr.pva.seg := segment;
      sequence_ptr_convtr.pva.offset := #OFFSET (p_object^.file_label) - object_info_offset_difference;
      p_object^.file_label := sequence_ptr_convtr.p_sequence;
    IFEND;

    status.normal := TRUE;
  PROCEND convert_cycle_object_pointers;

?? TITLE := '  convert_file_object_pointers', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to convert pvas, within a file object of
{   the object information sequence, which are valid on the server to pvas
{   which are valid on the client.

  PROCEDURE convert_file_object_pointers
    (    object_info_offset_difference: ost$segment_offset;
         p_object: {i^/o^} ^fst$goi_object;
     VAR p_object_information: {i/o} ^SEQ ( * );
     VAR status: ost$status);

    VAR
      adaptable_array_ptr_convtr: adaptable_array_ptr_converter,
      object_index: ost$positive_integers,
      p_file_information: ^fst$goi_file_information,
      p_object_list: ^fst$goi_object_list,
      ring: ost$valid_ring,
      segment: ost$segment;

    ring := #RING (p_object_information);
    segment := #SEGMENT (p_object_information);

    IF p_object^.applicable_file_permit <> NIL THEN
      p_object^.applicable_file_permit := #ADDRESS (ring, segment,
            #OFFSET (p_object^.applicable_file_permit) - object_info_offset_difference);
    IFEND;

    IF p_object^.file_information <> NIL THEN
      p_object^.file_information := #ADDRESS (ring, segment,
            #OFFSET (p_object^.file_information) - object_info_offset_difference);

      RESET p_object_information TO p_object^.file_information;
      NEXT p_file_information IN p_object_information;
      IF p_file_information = NIL THEN
        osp$set_status_abnormal (pfc$permanent_file_manager_id, pfe$pf_system_error,
              'p_file_information = NIL  convert_file_object_pointers', status);
        RETURN;
      IFEND;

      p_file_information^.logging_selection := #ADDRESS (ring, segment,
            #OFFSET (p_file_information^.logging_selection) - object_info_offset_difference);
    IFEND;

    IF p_object^.file_log <> NIL THEN
      adaptable_array_ptr_convtr.p_log_array := p_object^.file_log;
      adaptable_array_ptr_convtr.pva.ring := ring;
      adaptable_array_ptr_convtr.pva.seg := segment;
      adaptable_array_ptr_convtr.pva.offset := #OFFSET (p_object^.file_log) - object_info_offset_difference;
      p_object^.file_log := adaptable_array_ptr_convtr.p_log_array;
    IFEND;

    IF p_object^.file_permits <> NIL THEN
      adaptable_array_ptr_convtr.p_permit_array := p_object^.file_permits;
      adaptable_array_ptr_convtr.pva.ring := ring;
      adaptable_array_ptr_convtr.pva.seg := segment;
      adaptable_array_ptr_convtr.pva.offset :=
            #OFFSET (p_object^.file_permits) - object_info_offset_difference;
      p_object^.file_permits := adaptable_array_ptr_convtr.p_permit_array;
    IFEND;

    IF p_object^.cycle_object_list <> NIL THEN
      adaptable_array_ptr_convtr.p_object_list := p_object^.cycle_object_list;
      adaptable_array_ptr_convtr.pva.ring := ring;
      adaptable_array_ptr_convtr.pva.seg := segment;
      adaptable_array_ptr_convtr.pva.offset :=
            #OFFSET (p_object^.cycle_object_list) - object_info_offset_difference;
      p_object^.cycle_object_list := adaptable_array_ptr_convtr.p_object_list;

      RESET p_object_information TO p_object^.cycle_object_list;
      NEXT p_object_list: [1 .. UPPERBOUND (p_object^.cycle_object_list^)] IN p_object_information;
      IF p_object_list = NIL THEN
        osp$set_status_abnormal (pfc$permanent_file_manager_id, pfe$pf_system_error,
              'p_object_list = NIL  convert_file_object_pointers', status);
        RETURN;
      IFEND;

      FOR object_index := 1 TO UPPERBOUND (p_object_list^) DO
        IF p_object_list^ [object_index].object_type = fsc$goi_cycle_object THEN
          convert_cycle_object_pointers (object_info_offset_difference, ^p_object_list^ [object_index],
                p_object_information, status);
        ELSE
          osp$set_status_abnormal (pfc$permanent_file_manager_id, pfe$pf_system_error,
                'Invalid object_type in cycle_object_list.  convert_file_object_pointers', status);
        IFEND;
        IF NOT status.normal THEN
          RETURN;
        IFEND;
      FOREND;
    IFEND;

    status.normal := TRUE;
  PROCEND convert_file_object_pointers;

?? TITLE := '  [INLINE] convert_group_to_authority', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to convert type pft$group to type
{   pft$authority.

  PROCEDURE [INLINE] convert_group_to_authority
    (    group: pft$group;
     VAR authority: pft$authority);

    authority.ownership := $pft$ownership [];
    authority.family := osc$null_name;
    authority.user := osc$null_name;
    authority.account := osc$null_name;
    authority.project := osc$null_name;

    CASE group.group_type OF
    = pfc$public =
      ;
    = pfc$family =
      authority.family := group.family_description.family;
    = pfc$account =
      authority.family := group.account_description.family;
      authority.account := group.account_description.account;
    = pfc$project =
      authority.family := group.project_description.family;
      authority.account := group.project_description.account;
      authority.project := group.project_description.project;
    = pfc$user =
      authority.family := group.user_description.family;
      authority.user := group.user_description.user;
    = pfc$user_account =
      authority.family := group.user_account_description.family;
      authority.account := group.user_account_description.account;
      authority.user := group.user_account_description.user;
    = pfc$member =
      authority.family := group.member_description.family;
      authority.account := group.member_description.account;
      authority.project := group.member_description.project;
      authority.user := group.member_description.user;
    ELSE
      ;
    CASEND;
  PROCEND convert_group_to_authority;

?? TITLE := '  convert_object_info_pointers', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to convert pvas, within the object
{   information sequence, which are valid on the server to pvas which are valid
{   on the client.
{
{ NOTE:
{   The offsets must be converted, as well as the segment numbers, because the
{   server may not start the information at the same offset in the segment as
{   would the client for two reasons.  First, the server uses the upper most
{   512K bytes of the segment, thus starting the information in the middle of
{   the segment.  Second, the caller may have pushed the sequence onto a stack,
{   allocated it into the middle of a segment, or reset the sequence pointer to
{   other than the first byte of the sequence; and the server does not use the
{   same physical memory for output as was provided by the caller.

  PROCEDURE convert_object_info_pointers
    (    server_object_info_offset: ost$segment_offset;
         p_object_info: {i/o^} ^fst$goi_object_information;
         p_object_information: {i/o^} ^SEQ ( * );
     VAR status: ost$status);

    VAR
      adaptable_string_ptr_convtr: adaptable_string_ptr_converter,
      object_info_offset_difference: ost$segment_offset,
      p_local_object_information: ^SEQ ( * ),
      p_object: ^fst$goi_object;

    p_local_object_information := p_object_information;
    object_info_offset_difference := server_object_info_offset - #OFFSET (p_object_info);

    IF p_object_info^.resolved_path <> NIL THEN
      adaptable_string_ptr_convtr.p_file_reference := p_object_info^.resolved_path;
      adaptable_string_ptr_convtr.pva.ring := #RING (p_local_object_information);
      adaptable_string_ptr_convtr.pva.seg := #SEGMENT (p_local_object_information);
      adaptable_string_ptr_convtr.pva.offset :=
            #OFFSET (p_object_info^.resolved_path) - object_info_offset_difference;
      p_object_info^.resolved_path := adaptable_string_ptr_convtr.p_file_reference;
    IFEND;

    IF p_object_info^.object <> NIL THEN
      p_object_info^.object := #ADDRESS (#RING (p_local_object_information),
            #SEGMENT (p_local_object_information),
            #OFFSET (p_object_info^.object) - object_info_offset_difference);

      RESET p_local_object_information TO p_object_info^.object;
      NEXT p_object IN p_local_object_information;
      IF p_object = NIL THEN
        osp$set_status_abnormal (pfc$permanent_file_manager_id, pfe$pf_system_error,
              'p_object = NIL in convert_object_info_pointers', status);
        RETURN;
      IFEND;

      CASE p_object^.object_type OF
      = fsc$goi_catalog_object =
        convert_catalog_object_pointers (object_info_offset_difference, p_object, p_local_object_information,
              status);
      = fsc$goi_file_object =
        convert_file_object_pointers (object_info_offset_difference, p_object, p_local_object_information,
              status);
      = fsc$goi_cycle_object =
        convert_cycle_object_pointers (object_info_offset_difference, p_object, p_local_object_information,
              status);
      ELSE
        osp$set_status_abnormal (pfc$permanent_file_manager_id, pfe$pf_system_error,
              'Invalid object_type in convert_object_info_pointers.', status);
      CASEND;
      IF NOT status.normal THEN
        RETURN;
      IFEND;
    IFEND;

    status.normal := TRUE;
  PROCEND convert_object_info_pointers;

?? TITLE := '  cycle_condition', EJECT ??

  FUNCTION [INLINE, UNSAFE] cycle_condition
    (    p_catalog_file: {input^} pft$p_catalog_file;
         p_physical_cycle: ^pft$physical_cycle): fst$file_access_condition;

    VAR
      file_duplicated: boolean,
      local_status: ost$status;

    cycle_condition := fsc$null_file_access_condition;
    IF (p_physical_cycle <> NIL) THEN
      IF p_physical_cycle^.cycle_entry.data_residence = pfc$offline_data THEN
        pfp$check_archive_entries (p_catalog_file, p_physical_cycle, file_duplicated, local_status);
        IF local_status.normal AND file_duplicated THEN
          cycle_condition := fsc$data_retrieval_required;
        ELSE
          cycle_condition := fsc$data_restoration_required;
        IFEND;
      ELSE
        cycle_condition := fsc$data_restoration_required;
      IFEND;
    IFEND;

  FUNCEND cycle_condition;
?? TITLE := '  [INLINE] determine_access_modes', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to determine the total modes of access for
{   which the cycle is attached throughout the system and the total modes of
{   access for which the cycle cannot be attached within the system.

  PROCEDURE [INLINE] determine_access_modes
    (    attach_status: pft$attach_status;
     VAR outstanding_access_modes: pft$usage_selections;
     VAR prevented_access_modes: pft$usage_selections);

    VAR
      usage_option: pft$usage_options;

    outstanding_access_modes := $pft$usage_selections [];
    prevented_access_modes := $pft$usage_selections [];

    IF attach_status.attach_count > 0 THEN
      FOR usage_option := LOWERVALUE (usage_option) TO UPPERVALUE (usage_option) DO
        IF attach_status.usage_counts [usage_option] > 0 THEN
          outstanding_access_modes := outstanding_access_modes + $pft$usage_selections [usage_option];
        IFEND;

        IF attach_status.prevent_usage_counts [usage_option] > 0 THEN
          prevented_access_modes := prevented_access_modes + $pft$usage_selections [usage_option];
        IFEND;
      FOREND;
    IFEND;
  PROCEND determine_access_modes;

?? TITLE := '  determine_mainframe_concurrency', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to determine if a cycle is attached on
{   this mainframe and/or on another mainframe, or on no mainframe; and whether
{   it isn't attached for write, or whether it may be shared for write on this
{   mainframe, or whether it may be shared for write between mainframes.
{
{ NOTE:
{   Until mainframe write concurrency is actually implemented,
{   fsc$shared_mass_storage really means "the cycle is attached for write on
{   another mainframe and mainframe write concurrency is not allowed."

  PROCEDURE determine_mainframe_concurrency
    (    binary_mainframe_id: pmt$binary_mainframe_id;
         cycle_entry: pft$cycle_entry;
         prevented_access_modes: pft$usage_selections;
         p_catalog_file: {input^} ^pft$catalog_file;
     VAR mainframe_usage_concurrency: fst$mainframe_usage_concurrency;
     VAR mainframe_write_concurrency: fst$mainframe_write_concurrency);

    VAR
      mainframe_usage_index: pft$mainframe_usage_index,
      p_mainframe_usage_list: ^pft$mainframe_usage_list;

    IF cycle_entry.attach_status.attach_count = 0 THEN
      mainframe_usage_concurrency := $fst$mainframe_usage_concurrency [];
      mainframe_write_concurrency := fsc$not_attached_for_write;
      RETURN;
    IFEND;

    IF cycle_entry.first_mainframe_usage_entry.entry_type = pfc$free_mainframe_entry THEN
      mainframe_usage_concurrency := $fst$mainframe_usage_concurrency [];
      IF $pft$usage_selections [pfc$append, pfc$modify, pfc$shorten] <= prevented_access_modes THEN
        {
        { unwilling to share for any form of write
        {
        mainframe_write_concurrency := fsc$not_attached_for_write;
      ELSE
        mainframe_write_concurrency := fsc$shared_memory;
      IFEND;
    ELSE
      IF cycle_entry.first_mainframe_usage_entry.attach_count = 0 THEN
        mainframe_usage_concurrency := $fst$mainframe_usage_concurrency [];
      ELSEIF cycle_entry.first_mainframe_usage_entry.mainframe_id = binary_mainframe_id THEN
        mainframe_usage_concurrency := $fst$mainframe_usage_concurrency [fsc$attached_on_this_mainframe];
      ELSE
        mainframe_usage_concurrency := $fst$mainframe_usage_concurrency [fsc$attached_on_other_mainframe];
      IFEND;

      IF cycle_entry.first_mainframe_usage_entry.write_count = 0 THEN
        IF $pft$usage_selections [pfc$append, pfc$modify, pfc$shorten] <= prevented_access_modes THEN
          {
          { unwilling to share for any form of write
          {
          mainframe_write_concurrency := fsc$not_attached_for_write;
        ELSE
          mainframe_write_concurrency := fsc$shared_memory;
        IFEND;
      ELSEIF cycle_entry.first_mainframe_usage_entry.mainframe_id = binary_mainframe_id THEN
        mainframe_write_concurrency := fsc$shared_memory;
      ELSE
        mainframe_write_concurrency := fsc$shared_mass_storage;
      IFEND;
    IFEND;

    pfp$build_mainfram_list_pointer (cycle_entry.mainframe_usage_list_locator, p_catalog_file,
          p_mainframe_usage_list);
    IF p_mainframe_usage_list <> NIL THEN
      FOR mainframe_usage_index := 1 TO UPPERBOUND (p_mainframe_usage_list^) DO
        IF p_mainframe_usage_list^ [mainframe_usage_index].mainframe_usage.entry_type =
              pfc$normal_mainframe_entry THEN
          IF p_mainframe_usage_list^ [mainframe_usage_index].mainframe_usage.attach_count > 0 THEN
            IF p_mainframe_usage_list^ [mainframe_usage_index].mainframe_usage.mainframe_id =
                  binary_mainframe_id THEN
              mainframe_usage_concurrency := mainframe_usage_concurrency +
                    $fst$mainframe_usage_concurrency [fsc$attached_on_this_mainframe];
            ELSE
              mainframe_usage_concurrency := mainframe_usage_concurrency +
                    $fst$mainframe_usage_concurrency [fsc$attached_on_other_mainframe];
            IFEND;
          IFEND;

          IF (p_mainframe_usage_list^ [mainframe_usage_index].mainframe_usage.write_count > 0) AND
                (mainframe_write_concurrency <> fsc$shared_mass_storage) THEN
            IF p_mainframe_usage_list^ [mainframe_usage_index].mainframe_usage.mainframe_id =
                  binary_mainframe_id THEN
              mainframe_write_concurrency := fsc$shared_memory;
            ELSE
              mainframe_write_concurrency := fsc$shared_mass_storage;
            IFEND;
          IFEND;
        IFEND;
      FOREND;
    IFEND;
  PROCEND determine_mainframe_concurrency;

?? TITLE := '  find_family_location', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to determine on which mainframe the
{   specified family resides.

  PROCEDURE find_family_location
    (    family_name: ost$family_name;
     VAR served_family: boolean;
     VAR served_family_locator: pft$served_family_locator);

    VAR
      p_queue_interface_table: dft$p_queue_interface_table,
      queue_index: dft$queue_index,
      self_serving: boolean,
      server_state: dft$server_state;

    served_family_locator.server_location.server_location_selector := dfc$served_family_table_index;
    dfp$locate_served_family (family_name, served_family, served_family_locator.served_family_table_index,
          served_family_locator.server_mainframe_id,
          p_queue_interface_table,
          queue_index, server_state);
    IF served_family THEN
      served_family_locator.server_location.served_family_table_index :=
            served_family_locator.served_family_table_index;
      dfp$check_self_serving_job (served_family_locator.server_mainframe_id, self_serving);
      served_family := NOT self_serving;
    IFEND;
  PROCEND find_family_location;

?? TITLE := '  get_attached_cycle_information', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to get the requested information about a
{   cycle which is attached within the job.

  PROCEDURE get_attached_cycle_information
    (    evaluated_file_reference: fst$evaluated_file_reference;
         information_request: fst$goi_information_request;
         p_cycle_description: {input^} ^fmt$cycle_description;
         password_selector: pft$password_selector;
         validation_ring: ost$valid_ring;
         p_object_info: {output^} ^fst$goi_object_information;
     VAR p_object_information: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      eoi: amt$file_byte_address,
      family_name: ost$family_name,
      file_previously_opened: boolean,
      local_status: ost$status,
      object_information_requests: fst$goi_object_info_requests,
      p_size: ^amt$file_byte_address,
      served_family: boolean,
      served_family_locator: pft$served_family_locator;

    object_information_requests := information_request.object_information_requests;

    IF object_information_requests * $fst$goi_object_info_requests [fsc$goi_set_name,
          fsc$goi_cycle_device_info, fsc$goi_job_environment_info, fsc$goi_file_label] <>
          $fst$goi_object_info_requests [] THEN
      family_name := fsp$path_element (^evaluated_file_reference, 1)^;
      find_family_location (family_name, served_family, served_family_locator);

      IF fsc$goi_set_name IN object_information_requests THEN
        IF served_family THEN
          pfp$r2_df_client_get_family_set (family_name, served_family_locator, p_object_info^.set_name,
                status);
        ELSE
          osp$get_set_name (family_name, p_object_info^.set_name, status);
        IFEND;
      IFEND;
    IFEND;

    store_resolved_path (evaluated_file_reference, p_object_info, p_object_information, local_status);
    IF NOT local_status.normal THEN
      IF local_status.condition = pfe$info_full THEN
        status := local_status;
        RETURN;
      ELSEIF status.normal THEN
        status := local_status;
      IFEND;
    IFEND;

    IF ((object_information_requests - pfv$catalog_info_requests = $fst$goi_object_info_requests []) AND
          (evaluated_file_reference.number_of_path_elements > 1)) OR
          (object_information_requests = $fst$goi_object_info_requests []) THEN
      RETURN;
    IFEND;

    NEXT p_object_info^.object IN p_object_information;
    IF p_object_info^.object = NIL THEN
      osp$set_status_condition (pfe$info_full, status);
      RETURN;
    IFEND;

    initialize_cycle_object (evaluated_file_reference.cycle_reference.cycle_number,
          p_cycle_description^.system_file_label.descriptive_label.global_file_name,
          p_cycle_description^.device_class, {validation_error} FALSE, p_object_info^.object);

    IF fsc$goi_cycle_device_info IN object_information_requests THEN
      pfp$get_attached_device_info ({temporary_file} FALSE, served_family, ^served_family_locator,
            p_cycle_description, p_object_info^.object, p_object_information, eoi, local_status);
      IF NOT local_status.normal THEN
        IF local_status.condition = pfe$info_full THEN
          status := local_status;
          RETURN;
        ELSEIF status.normal THEN
          status := local_status;
        IFEND;
      IFEND;
    IFEND;

  /get_cycle_size/
    BEGIN
      IF (fsc$goi_cycle_size IN object_information_requests) AND (p_cycle_description^.device_class =
            rmc$mass_storage_device) THEN
        NEXT p_size IN p_object_information;
        IF p_size = NIL THEN
          osp$set_status_condition (pfe$info_full, status);
          RETURN;
        IFEND;

        IF p_cycle_description^.global_file_information^.eoi_set AND
              (p_cycle_description^.attached_share_modes <= $fst$file_access_options [fsc$execute, fsc$read])
              THEN
          p_size^ := p_cycle_description^.global_file_information^.eoi_byte_address;
        ELSEIF fsc$goi_cycle_device_info IN object_information_requests THEN
          p_size^ := eoi;
        ELSE
          dmp$fetch_eoi (p_cycle_description^.system_file_id, p_size^, local_status);
          IF NOT local_status.normal THEN
            IF status.normal THEN
              status := local_status;
            IFEND;
            EXIT /get_cycle_size/;
          IFEND;
        IFEND;

        p_object_info^.object^.cycle_size := p_size;
      IFEND;
    END /get_cycle_size/;

    IF (fsc$goi_job_environment_info IN object_information_requests) OR
          (fsc$goi_file_label IN object_information_requests) THEN
      get_protected_info_from_cd (served_family, served_family_locator, evaluated_file_reference,
            object_information_requests, p_cycle_description, password_selector, validation_ring,
            p_object_info^.object, p_object_information, status);
      IF (NOT local_status.normal) AND (status.normal OR (local_status.condition = pfe$info_full)) THEN
        status := local_status;
      IFEND;
    IFEND;
  PROCEND get_attached_cycle_information;

?? TITLE := '  get_catalog_object_information', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to get the requested information about the
{   specified catalog.

  PROCEDURE get_catalog_object_information
    (    family_location: pft$family_location;
         binary_mainframe_id: pmt$binary_mainframe_id;
         path: pft$complete_path;
         information_request: fst$goi_information_request;
         current_depth: fst$path_element_index;
         authority: pft$authority;
         permit_entry: pft$permit_entry;
         p_physical_object: {input^} ^pft$physical_object;
         password_selector: pft$password_selector;
         validation_ring: ost$valid_ring;
         p_subject_permit_id_list: {i/o^} ^subject_permit_id_list;
         p_object: {output^} ^fst$goi_object;
     VAR catalog_locator: {i/o} pft$catalog_locator;
     VAR permitted_to_catalog: {i/o} boolean;
     VAR p_object_information: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      device_information_initialized: boolean,
      dm_file_information: dmt$file_information,
      global_file_name: ost$binary_unique_name,
      local_date_time: ost$date_time,
      local_status: ost$status,
      local_time_zone: ost$time_zone,
      object_information_requests: fst$goi_object_info_requests,
      p_device_information: ^fst$device_information,
      p_physical_fmd: ^pft$physical_fmd,
      p_size: ^amt$file_byte_address;

     VAR
      catalog: boolean,
      catalog_recreated: boolean,
      cycle_selector: pft$cycle_selector,
      device_class: rmt$device_class,
      file_gfn: ost$binary_unique_name,
      fmd_size: dmt$stored_fmd_size,
      p_stored_fmd: ^dmt$stored_fmd;

    object_information_requests := information_request.object_information_requests;

    IF fsc$goi_applicable_cat_permit IN object_information_requests THEN
      NEXT p_object^.applicable_catalog_permit IN p_object_information;
      IF p_object^.applicable_catalog_permit = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;

      p_object^.applicable_catalog_permit^.permit_type := pfc$indirect_permit;
      p_object^.applicable_catalog_permit^.group := permit_entry.group;
      p_object^.applicable_catalog_permit^.usage_permissions := permit_entry.usage_permissions;
      p_object^.applicable_catalog_permit^.share_requirements := permit_entry.share_requirements;
      p_object^.applicable_catalog_permit^.application_info := permit_entry.application_info;
    IFEND;

    IF (fsc$goi_catalog_device_info IN object_information_requests) THEN
      IF p_physical_object^.object_entry.catalog_object_locator.catalog_type = pfc$external_catalog THEN
        pfp$build_fmd_pointer (p_physical_object^.object_entry.catalog_object_locator.fmd_locator,
              catalog_locator.p_catalog_file, p_physical_fmd);

        IF p_physical_fmd = NIL THEN
          p_device_information := NIL;
          status.normal := TRUE;
        ELSE
          NEXT p_device_information IN p_object_information;
          IF p_device_information = NIL THEN
            osp$set_status_condition (pfe$info_full, status);
            RETURN;
          IFEND;

          get_disk_device_info_from_fmd (^p_physical_fmd^.fmd, p_device_information,
                device_information_initialized, p_object_information, status);
          IF (NOT status.normal) AND (status.condition = pfe$info_full) THEN
            RETURN;
          ELSEIF NOT device_information_initialized THEN
            p_device_information := NIL;
          IFEND;
          {
          { Bytes_allocated cannot be retrieved without attaching the catalog.
          { The catalog must not be attached yet, but will be attached below.
          {
        IFEND;
      ELSE
        cycle_selector.cycle_option := pfc$highest_cycle;
        pfp$r2_get_stored_fmd_size (path, cycle_selector, device_class, file_gfn, fmd_size, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;

        PUSH p_stored_fmd: [[REP fmd_size OF cell]];
        IF p_stored_fmd = NIL THEN
          p_device_information := NIL;
          status.normal := TRUE;
        ELSE
          pfp$r2_get_stored_fmd (path, cycle_selector, catalog, catalog_recreated, file_gfn,
              p_stored_fmd^, status);
          IF status.normal THEN
            NEXT p_device_information IN p_object_information;
            IF p_device_information = NIL THEN
              osp$set_status_condition (pfe$info_full, status);
              RETURN;
            IFEND;

            get_disk_device_info_from_fmd (p_stored_fmd, p_device_information,
                  device_information_initialized, p_object_information, status);
            IF (NOT status.normal) AND (status.condition = pfe$info_full) THEN
              RETURN;
            ELSEIF NOT device_information_initialized THEN
              p_device_information := NIL;
            IFEND;
            {
            { Bytes_allocated cannot be retrieved without attaching the catalog.
            { The catalog must not be attached yet, but will be attached below.
            {
          ELSEIF status.condition = pfe$catalog_access_retry THEN
            RETURN;
          IFEND;
        IFEND;
      IFEND;
    ELSE
      p_device_information := NIL;
      status.normal := TRUE;
    IFEND;

    IF fsc$goi_catalog_info IN object_information_requests THEN
      NEXT p_object^.catalog_information IN p_object_information;
      IF p_object^.catalog_information = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;

      p_object^.catalog_information^.account := p_physical_object^.object_entry.charge_id.account;
      global_file_name := p_physical_object^.object_entry.internal_object_name;
      p_object^.catalog_information^.creation_date_time.year := global_file_name.year - 1900;
      p_object^.catalog_information^.creation_date_time.month := global_file_name.month;
      p_object^.catalog_information^.creation_date_time.day := global_file_name.day;
      p_object^.catalog_information^.creation_date_time.hour := global_file_name.hour;
      p_object^.catalog_information^.creation_date_time.minute := global_file_name.minute;
      p_object^.catalog_information^.creation_date_time.second := global_file_name.second;
      p_object^.catalog_information^.creation_date_time.millisecond := 000;
      p_object^.catalog_information^.project := p_physical_object^.object_entry.charge_id.project;
      {
      { Here the creation_date_time is converted to local_date_time
      {
      pmp$get_time_zone (local_time_zone, local_status);
      pmp$compute_local_date_time (p_object^.catalog_information^.creation_date_time, local_time_zone,
            local_date_time, local_status);
      p_object^.catalog_information^.creation_date_time := local_date_time;
    IFEND;

    IF fsc$goi_catalog_permits IN object_information_requests THEN
      get_permits (authority, p_physical_object^.object_entry.permit_list_locator,
            catalog_locator.p_catalog_file, p_object, p_object_information, local_status);
      IF NOT local_status.normal THEN
        status := local_status;
        RETURN;
      IFEND;
    IFEND;

    IF fsc$goi_catalog_size IN object_information_requests THEN
      NEXT p_size IN p_object_information;
      IF p_size = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;
      {
      { Catalog_size cannot be retrieved without attaching the catalog. The
      { catalog will be attached below.
      {
    IFEND;

    IF p_device_information <> NIL THEN
      IF p_physical_object^.object_entry.catalog_object_locator.catalog_type = pfc$external_catalog THEN
        get_object_condition ({catalog_object} TRUE, {served_family} FALSE,
             {p_served_family_locator} NIL, ^p_physical_fmd^.fmd,
             p_device_information^.mass_storage_device_info, p_object_information, status);
      ELSE
        get_object_condition ({catalog_object} TRUE, {served_family} FALSE,
             {p_served_family_locator} NIL, p_stored_fmd,
             p_device_information^.mass_storage_device_info, p_object_information, status);
      IFEND;
    IFEND;

    IF (p_device_information <> NIL) OR (fsc$goi_catalog_size IN object_information_requests) OR
          (object_information_requests * object_list_requests <> $fst$goi_object_info_requests []) OR
          (information_request.catalog_depth.depth_specification = fsc$entire_subtree) OR
          (current_depth < information_request.catalog_depth.depth) OR NOT permitted_to_catalog THEN
      attach_next_catalog (path, object_information_requests, p_physical_object, catalog_locator,
            local_status);
      IF NOT local_status.normal THEN
        IF osp$file_access_condition (local_status) THEN
          IF p_device_information <> NIL THEN
            p_device_information^.mass_storage_device_info.bytes_allocated := 16384;
            p_device_information^.mass_storage_device_info.shared_queue := osc$null_name;
            p_object^.catalog_device_information := p_device_information;
          IFEND;
        ELSEIF status.normal THEN
          status := local_status;
        IFEND;
        RETURN;
      IFEND;

    /get_bytes_allocated_and_eoi/
      BEGIN
        IF (p_device_information <> NIL) OR (fsc$goi_catalog_size IN object_information_requests) THEN
          dmp$get_file_info (catalog_locator.system_file_id, dm_file_information, local_status);
          IF NOT local_status.normal THEN
            IF status.normal THEN
              status := local_status;
            IFEND;
            EXIT /get_bytes_allocated_and_eoi/;
          IFEND;

          IF p_device_information <> NIL THEN
            p_device_information^.mass_storage_device_info.bytes_allocated :=
                  dm_file_information.total_allocated_length;
            p_device_information^.mass_storage_device_info.shared_queue := osc$null_name;
            IF status.normal THEN
              p_object^.catalog_device_information := p_device_information;
            IFEND;
          IFEND;

          IF fsc$goi_catalog_size IN object_information_requests THEN
            p_size^ := dm_file_information.eoi_byte_address;
            p_object^.catalog_size := p_size;
          IFEND;
        IFEND;
      END /get_bytes_allocated_and_eoi/;

      IF (catalog_locator.object_list_descriptor.p_object_list <> NIL) AND
            ((object_information_requests * object_list_requests <> $fst$goi_object_info_requests []) OR
            (information_request.catalog_depth.depth_specification = fsc$entire_subtree) OR
            (current_depth < information_request.catalog_depth.depth) OR NOT permitted_to_catalog) THEN
        get_object_list_information (family_location, binary_mainframe_id, path, information_request,
              current_depth, authority, permit_entry, password_selector, validation_ring,
              p_subject_permit_id_list, p_object, catalog_locator, permitted_to_catalog, p_object_information,
              local_status);
        IF (NOT local_status.normal) AND (status.normal OR (local_status.condition = pfe$info_full)) THEN
          status := local_status;
        IFEND;
      IFEND;
    IFEND;
  PROCEND get_catalog_object_information;

?? TITLE := '  get_cycle_list_information', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to get the requested information about the
{   specified cycle(s).

  PROCEDURE get_cycle_list_information
    (    family_location: pft$family_location;
         binary_mainframe_id: pmt$binary_mainframe_id;
         path: pft$complete_path;
         object_information_requests: fst$goi_object_info_requests;
         authority: pft$authority;
         p_physical_object: {input^} ^pft$physical_object;
         p_catalog_file: {input^} ^pft$catalog_file;
         password_selector: pft$password_selector;
         validation_ring: ost$valid_ring;
         p_physical_cycle: {i/o^} ^pft$physical_cycle;
         p_object: {output^} ^fst$goi_object;
     VAR p_object_information: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      cycle_count: pft$cycle_count,
      cycle_index: pft$cycle_index,
      cycle_info_requested: fst$goi_object_info_requests,
      cycle_selector: pft$cycle_selector,
      device_class: rmt$device_class,
      local_status: ost$status,
      p_cycle_list: ^pft$cycle_list,
      p_local_physical_cycle: ^pft$physical_cycle,
      password_status: ost$status;

    cycle_info_requested := object_information_requests * pfv$cycle_info_requests;

    IF cycle_info_requested * protected_info_requests = $fst$goi_object_info_requests [] THEN
      password_status.normal := TRUE;
    ELSEIF password_selector.password_specified = pfc$default_password_option THEN
      pfp$validate_password (path, authority, osc$null_name, p_physical_object, password_status);
    ELSE
      pfp$validate_password (path, authority, password_selector.password, p_physical_object, password_status);
    IFEND;

    IF fsc$goi_cycle_object_list IN object_information_requests THEN
      pfp$build_cycle_list_pointer (p_physical_object^.object_entry.cycle_list_locator, p_catalog_file,
            p_cycle_list);
      IF p_cycle_list = NIL THEN
        IF NOT password_status.normal THEN
          status := password_status;
        ELSE
          status.normal := TRUE;
        IFEND;
        RETURN;
      IFEND;

      cycle_count := 0;
      FOR cycle_index := 1 TO UPPERBOUND (p_cycle_list^) DO
        IF p_cycle_list^ [cycle_index].cycle_entry.entry_type = pfc$normal_cycle_entry THEN
          cycle_count := cycle_count + 1;
        IFEND;
      FOREND;

      NEXT p_object^.cycle_object_list: [1 .. cycle_count] IN p_object_information;
      IF p_object^.cycle_object_list = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;

      cycle_count := 0;
      cycle_info_requested := cycle_info_requested -
            $fst$goi_object_info_requests [fsc$goi_cycle_identity, fsc$goi_job_environment_info];
      status.normal := TRUE;

      FOR cycle_index := 1 TO UPPERBOUND (p_cycle_list^) DO
        IF p_cycle_list^ [cycle_index].cycle_entry.entry_type = pfc$normal_cycle_entry THEN
          p_local_physical_cycle := ^p_cycle_list^ [cycle_index];
          cycle_count := cycle_count + 1;

          IF p_local_physical_cycle^.cycle_entry.device_information.device_class_defined THEN
            pfp$convert_device_class_to_rm (
                  p_local_physical_cycle^.cycle_entry.device_information.device_class, device_class);
          ELSE
            device_class := rmc$mass_storage_device;
          IFEND;

          initialize_cycle_object (p_local_physical_cycle^.cycle_entry.cycle_number,
                p_local_physical_cycle^.cycle_entry.global_file_name, device_class,
                {validation_error} NOT password_status.normal, ^p_object^.cycle_object_list^ [cycle_count]);

          IF (status.normal OR (status.condition <> pfe$info_full)) AND
                (cycle_info_requested <> $fst$goi_object_info_requests []) THEN
            get_cycle_object_information (family_location, binary_mainframe_id, path, cycle_info_requested,
                  authority, p_physical_object, validation_ring, p_local_physical_cycle, p_catalog_file,
                  ^p_object^.cycle_object_list^ [cycle_count], p_object_information, local_status);
            IF (NOT local_status.normal) AND (status.normal OR (local_status.condition = pfe$info_full)) THEN
              status := local_status;
            IFEND;
          IFEND;
        IFEND;
      FOREND;

    ELSE {cycle_info_requested <> $fst$goi_object_info_requests []}
      IF p_physical_cycle = NIL THEN
        pfp$build_cycle_list_pointer (p_physical_object^.object_entry.cycle_list_locator, p_catalog_file,
              p_cycle_list);
        cycle_selector.cycle_option := pfc$highest_cycle;
        pfp$locate_cycle (path, p_cycle_list, cycle_selector, p_local_physical_cycle, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
      ELSE
        p_local_physical_cycle := p_physical_cycle;
      IFEND;

      IF p_local_physical_cycle^.cycle_entry.device_information.device_class_defined THEN
        pfp$convert_device_class_to_rm (
              p_local_physical_cycle^.cycle_entry.device_information.device_class, device_class);
      ELSE
        device_class := rmc$mass_storage_device;
      IFEND;

      NEXT p_object^.cycle_object_list: [1 .. 1] IN p_object_information;
      IF p_object^.cycle_object_list = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;

      initialize_cycle_object (p_local_physical_cycle^.cycle_entry.cycle_number,
            p_local_physical_cycle^.cycle_entry.global_file_name, device_class,
            {validation_error} NOT password_status.normal, ^p_object^.cycle_object_list^ [1]);

      IF cycle_info_requested -
            $fst$goi_object_info_requests [fsc$goi_cycle_identity, fsc$goi_job_environment_info] <>
            $fst$goi_object_info_requests [] THEN
        get_cycle_object_information (family_location, binary_mainframe_id, path, cycle_info_requested,
              authority, p_physical_object, validation_ring, p_local_physical_cycle, p_catalog_file,
              ^p_object^.cycle_object_list^ [1], p_object_information, status);
      ELSE
        status.normal := TRUE;
      IFEND;

      IF p_physical_cycle <> NIL THEN
        p_physical_cycle^ := p_local_physical_cycle^;
      IFEND;
    IFEND;

    IF (NOT password_status.normal) AND (status.normal OR (status.condition = pfe$invalid_ring_access) OR
          (status.condition = ame$damaged_file_attributes)) THEN
      status := password_status;
    IFEND;
  PROCEND get_cycle_list_information;

?? TITLE := '  get_cycle_object_information', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to get the requested information about the
{   specified cycle.

  PROCEDURE get_cycle_object_information
    (    family_location: pft$family_location;
         binary_mainframe_id: pmt$binary_mainframe_id;
         path: pft$complete_path;
         object_information_requests: fst$goi_object_info_requests;
         authority: pft$authority;
         p_physical_object: {input^} ^pft$physical_object;
         validation_ring: ost$valid_ring;
         p_physical_cycle: {i^/o^} ^pft$physical_cycle;
         p_catalog_file: {i^/o^} ^pft$catalog_file;
         p_object: {output^} ^fst$goi_object;
     VAR p_object_information: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      archive_entry: pft$archive_entry,
      archive_index: pft$archive_index,
      attached_for_write: boolean,
      cycle_entry: pft$cycle_entry,
      device_class: rmt$device_class,
      device_information_initialized: boolean,
      dm_file_information: dmt$file_information,
      dm_file_information_valid: boolean,
      local_status: ost$status,
      p_archive_list: ^pft$archive_list,
      p_device_information: ^fst$device_information,
      p_file_label: ^fmt$file_label,
      p_physical_amd: ^pft$physical_amd,
      p_physical_file_label: ^pft$physical_file_label,
      p_physical_fmd: ^pft$physical_fmd,
      p_size: ^amt$file_byte_address,
      served_family: boolean,
      served_family_locator: pft$served_family_locator,
      shared_queue_name: ost$name,
      stale_cycle_entry: boolean;

    IF fsc$goi_archive_info IN object_information_requests THEN
      pfp$build_archive_list_pointer (p_physical_cycle^.cycle_entry.archive_list_locator, p_catalog_file,
            p_archive_list);

      IF p_archive_list <> NIL THEN
        NEXT p_object^.archive_information_list: [1 .. UPPERBOUND (p_archive_list^)] IN p_object_information;
        IF p_object^.archive_information_list = NIL THEN
          osp$set_status_condition (pfe$info_full, status);
          RETURN;
        IFEND;

        FOR archive_index := 1 TO UPPERBOUND (p_archive_list^) DO
          archive_entry := p_archive_list^ [archive_index].archive_entry;
          p_object^.archive_information_list^ [archive_index].archive_entry.version := archive_entry.version;
          p_object^.archive_information_list^ [archive_index].archive_entry.archive_date_time :=
                archive_entry.archive_date_time;
          p_object^.archive_information_list^ [archive_index].archive_entry.archive_identification :=
                archive_entry.archive_identification;
          p_object^.archive_information_list^ [archive_index].archive_entry.file_size :=
                archive_entry.file_size;
          p_object^.archive_information_list^ [archive_index].archive_entry.last_release_date_time :=
                archive_entry.last_release_date_time;
          p_object^.archive_information_list^ [archive_index].archive_entry.last_retrieval_status :=
                archive_entry.last_retrieval_status;
          p_object^.archive_information_list^ [archive_index].archive_entry.modification_date_time :=
                archive_entry.modification_date_time;
          p_object^.archive_information_list^ [archive_index].archive_entry.release_candidate :=
                archive_entry.release_candidate;
          pfp$build_amd_pointer (archive_entry.amd_locator, p_catalog_file, p_physical_amd);
          IF p_physical_amd <> NIL THEN
            NEXT p_object^.archive_information_list^ [archive_index].amd:
                [[REP #SIZE (p_physical_amd^.amd) OF cell]] IN p_object_information;
            p_object^.archive_information_list^ [archive_index].amd^ := p_physical_amd^.amd;
          ELSE
            p_object^.archive_information_list^ [archive_index].amd := NIL;
          IFEND;
        FOREND;
      IFEND;
    IFEND;

    IF p_physical_cycle^.cycle_entry.device_information.device_class_defined THEN
      pfp$convert_device_class_to_rm (p_physical_cycle^.cycle_entry.device_information.device_class,
            device_class);
    ELSE
      device_class := rmc$mass_storage_device;
    IFEND;

  /get_cycle_device_info/
    BEGIN
      IF fsc$goi_cycle_device_info IN object_information_requests THEN
        NEXT p_device_information IN p_object_information;
        IF p_device_information = NIL THEN
          osp$set_status_condition (pfe$info_full, status);
          RETURN;
        IFEND;

        update_fmd (^path, family_location, p_physical_cycle, p_catalog_file, device_class, p_physical_fmd,
              attached_for_write, dm_file_information_valid, dm_file_information, status);
        IF NOT status.normal THEN
          EXIT /get_cycle_device_info/;
        IFEND;

        IF device_class = rmc$mass_storage_device THEN
          IF p_physical_cycle^.cycle_entry.shared_queue_info.defined THEN
            IF  dm_file_information_valid THEN
              pfp$convert_ord_to_shared_queue (dm_file_information.shared_queue, shared_queue_name,
                     status);
            ELSE
              pfp$convert_ord_to_shared_queue (p_physical_cycle^.cycle_entry.shared_queue_info.shared_queue,
                    shared_queue_name, status);
            IFEND;
            IF status.normal THEN
              p_device_information^.mass_storage_device_info.shared_queue := shared_queue_name;
            ELSE
              p_device_information^.mass_storage_device_info.shared_queue := pfc$system_shared_queue_name;
              status.normal := TRUE;
            IFEND;
          ELSE
            p_device_information^.mass_storage_device_info.shared_queue := pfc$system_shared_queue_name;
          IFEND;

          IF p_physical_fmd = NIL THEN
            p_device_information^.mass_storage_device_info.bytes_allocated :=
                  p_physical_cycle^.cycle_entry.device_information.bytes_allocated;
            p_device_information^.mass_storage_device_info.resides_online := FALSE;
            p_device_information^.mass_storage_device_info.object_condition := cycle_condition
                  (p_catalog_file, p_physical_cycle);
            p_object^.cycle_device_information := p_device_information;
          ELSE
            IF attached_for_write THEN
              IF dm_file_information_valid THEN
                p_device_information^.mass_storage_device_info.bytes_allocated :=
                      dm_file_information.total_allocated_length;
              ELSE
                p_device_information^.mass_storage_device_info.bytes_allocated :=
                      p_physical_cycle^.cycle_entry.device_information.bytes_allocated;
              IFEND;
            ELSE
              pfp$check_for_stale_cycle_entry (p_physical_cycle^.cycle_entry, stale_cycle_entry);

              IF stale_cycle_entry THEN
                update_stale_cycle_entry (family_location, ^path, p_physical_fmd^.fmd, p_physical_cycle,
                      p_catalog_file);
              IFEND;

              p_device_information^.mass_storage_device_info.bytes_allocated :=
                    p_physical_cycle^.cycle_entry.device_information.bytes_allocated;
            IFEND;

            get_disk_device_info_from_fmd (^p_physical_fmd^.fmd, p_device_information,
                  device_information_initialized, p_object_information, status);
            IF device_information_initialized THEN
              IF status.normal THEN
                find_family_location (path [pfc$family_path_index], served_family, served_family_locator);
                get_object_condition ({catalog_object} FALSE, served_family, ^served_family_locator,
                      ^p_physical_fmd^.fmd, p_device_information^.mass_storage_device_info,
                      p_object_information, status);
              IFEND;
              p_object^.cycle_device_information := p_device_information;
            IFEND;
          IFEND;
        ELSEIF (device_class = rmc$magnetic_tape_device) AND (p_physical_fmd <> NIL) THEN
          get_tape_device_info_from_fmd (^p_physical_fmd^.fmd, p_device_information, p_object_information,
                status);
          IF NOT status.normal THEN
            RETURN;
          IFEND;
          p_object^.cycle_device_information := p_device_information;
        IFEND;
      ELSE
        status.normal := TRUE;
      IFEND;
    END /get_cycle_device_info/;

    IF fsc$goi_cycle_info IN object_information_requests THEN
      NEXT p_object^.cycle_information IN p_object_information;
      IF p_object^.cycle_information = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;

      cycle_entry := p_physical_cycle^.cycle_entry;
      p_object^.cycle_information^.creation_date_time := cycle_entry.cycle_statistics.creation_date_time;
      p_object^.cycle_information^.damage_symptoms := cycle_entry.cycle_damage_symptoms;
      p_object^.cycle_information^.data_modification_date_time := cycle_entry.data_modification_date_time;
      p_object^.cycle_information^.expiration_date_time := cycle_entry.expiration_date_time;
      p_object^.cycle_information^.last_access_date_time := cycle_entry.cycle_statistics.access_date_time;
      p_object^.cycle_information^.last_modification_date_time :=
            cycle_entry.cycle_statistics.modification_date_time;
      p_object^.cycle_information^.lifetime_attachment_count := cycle_entry.cycle_statistics.access_count;
      determine_access_modes (cycle_entry.attach_status,
            p_object^.cycle_information^.outstanding_access_modes,
            p_object^.cycle_information^.prevented_access_modes);
      determine_mainframe_concurrency (binary_mainframe_id, cycle_entry,
            p_object^.cycle_information^.prevented_access_modes, p_catalog_file,
            p_object^.cycle_information^.mainframe_usage_concurrency,
            p_object^.cycle_information^.mainframe_write_concurrency);
      p_object^.cycle_information^.retrieve_option := cycle_entry.retrieve_option;
      p_object^.cycle_information^.site_backup_option := cycle_entry.site_backup_option;
      p_object^.cycle_information^.site_archive_option := cycle_entry.site_archive_option;
      p_object^.cycle_information^.site_release_option := cycle_entry.site_release_option;
      p_object^.cycle_information^.attachment_status := cycle_entry.attach_status;
    IFEND;

  /get_cycle_size/
    BEGIN
      IF (fsc$goi_cycle_size IN object_information_requests) AND (device_class = rmc$mass_storage_device) THEN
        NEXT p_size IN p_object_information;
        IF p_size = NIL THEN
          osp$set_status_condition (pfe$info_full, status);
          RETURN;
        IFEND;

        IF fsc$goi_cycle_device_info IN object_information_requests THEN
          IF dm_file_information_valid THEN
            p_size^ := dm_file_information.eoi_byte_address;
          ELSE
            p_size^ := p_physical_cycle^.cycle_entry.device_information.eoi;
          IFEND;
        ELSE
          update_fmd (^path, family_location, p_physical_cycle, p_catalog_file, device_class, p_physical_fmd,
                attached_for_write, dm_file_information_valid, dm_file_information, status);
          IF NOT status.normal THEN
            EXIT /get_cycle_size/;
          IFEND;

          IF attached_for_write THEN
            IF dm_file_information_valid THEN
              p_size^ := dm_file_information.eoi_byte_address;
            ELSE
              p_size^ := p_physical_cycle^.cycle_entry.device_information.eoi;
            IFEND;
          ELSE
            IF p_physical_fmd <> NIL THEN
              pfp$check_for_stale_cycle_entry (p_physical_cycle^.cycle_entry, stale_cycle_entry);

              IF stale_cycle_entry THEN
                update_stale_cycle_entry (family_location, ^path, p_physical_fmd^.fmd, p_physical_cycle,
                      p_catalog_file);
              IFEND;
            IFEND;

            p_size^ := p_physical_cycle^.cycle_entry.device_information.eoi;
          IFEND;
        IFEND;

        p_object^.cycle_size := p_size;
      IFEND;
    END /get_cycle_size/;

    IF (fsc$goi_file_label IN object_information_requests) AND NOT p_object^.validation_error THEN
      pfp$build_file_label_pointer (p_physical_cycle^.cycle_entry.file_label_locator, p_catalog_file,
            p_physical_file_label);
      IF p_physical_file_label <> NIL THEN
        pfp$validate_ring_access (path, ^p_physical_file_label^.file_label,
              $pft$usage_selections [pfc$execute], validation_ring, local_status);
        IF NOT local_status.normal THEN
          p_object^.validation_error := TRUE;
          IF status.normal THEN
            status := local_status;
          IFEND;
          RETURN;
        IFEND;

        NEXT p_file_label: [[REP p_physical_cycle^.cycle_entry.file_label_locator.file_label_size OF cell]]
              IN p_object_information;
        IF p_file_label = NIL THEN
          osp$set_status_condition (pfe$info_full, status);
          RETURN;
        IFEND;

        p_file_label^ := p_physical_file_label^.file_label;
        p_object^.file_label := p_file_label;
      IFEND;
    IFEND;
  PROCEND get_cycle_object_information;

?? TITLE := '  get_disk_device_info_from_fmd', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to get disk device information from an
{   fmd.

  PROCEDURE get_disk_device_info_from_fmd
    (    p_fmd: {input^} ^pft$fmd;
         p_device_information: {output^} ^fst$device_information;
     VAR device_information_initialized: boolean;
     VAR p_object_information: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      fmd_header: pft$fmd_header,
      p_volume_list: ^pft$volume_list,
      volume_index: dmt$subfile_index;

    dmp$get_stored_fmd_header_info (p_fmd, fmd_header, status);
    IF NOT status.normal THEN
      device_information_initialized := FALSE;
      RETURN;
    IFEND;

    p_device_information^.mass_storage_device_info.resides_online := TRUE;
    p_device_information^.mass_storage_device_info.allocation_unit_size :=
          fmd_header.requested_allocation_size;
    p_device_information^.mass_storage_device_info.initial_volume := fmd_header.requested_volume.recorded_vsn;
    p_device_information^.mass_storage_device_info.mass_storage_class := fmd_header.requested_class;
    p_device_information^.mass_storage_device_info.transfer_size := fmd_header.requested_transfer_size;
    p_device_information^.mass_storage_device_info.volume_overflow_allowed := fmd_header.overflow_allowed;
    p_device_information^.mass_storage_device_info.volume_condition_list := NIL;
    p_device_information^.mass_storage_device_info.volume_list := NIL;
    device_information_initialized := TRUE;

    PUSH p_volume_list: [1 .. fmd_header.number_of_subfiles];
    dmp$get_stored_fmd_volume_list (p_fmd, p_volume_list, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    NEXT p_device_information^.mass_storage_device_info.volume_list: [1 .. fmd_header.number_of_subfiles]
          IN p_object_information;
    IF p_device_information^.mass_storage_device_info.volume_list = NIL THEN
      osp$set_status_condition (pfe$info_full, status);
      RETURN;
    IFEND;

    FOR volume_index := 1 TO fmd_header.number_of_subfiles DO
      p_device_information^.mass_storage_device_info.volume_list^ [volume_index].recorded_vsn :=
            p_volume_list^ [volume_index];
      p_device_information^.mass_storage_device_info.volume_list^ [volume_index].external_vsn :=
            p_volume_list^ [volume_index];
    FOREND;
  PROCEND get_disk_device_info_from_fmd;
?? TITLE := '  get_file_object_information', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to get the requested information about the
{   specified file.

  PROCEDURE get_file_object_information
    (    family_location: pft$family_location;
         binary_mainframe_id: pmt$binary_mainframe_id;
         path: pft$complete_path;
         object_information_requests: fst$goi_object_info_requests;
         authority: pft$authority;
         permit_entry: pft$permit_entry;
         p_physical_object: {input^} ^pft$physical_object;
         p_catalog_file: {input^} ^pft$catalog_file;
         unknown_cycle: boolean;
         password_selector: pft$password_selector;
         validation_ring: ost$valid_ring;
         p_physical_cycle: {i/o^} ^pft$physical_cycle;
         p_object: {output^} ^fst$goi_object;
     VAR p_object_information: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      log_count: pft$log_count,
      log_index: pft$log_index,
      p_file_information: ^fst$goi_file_information,
      p_log_entry: ^pft$log_entry,
      p_log_list: ^pft$log_list,
      p_logging_selection: ^pft$log,
      user_id: ost$user_identification;

    IF fsc$goi_applicable_file_permit IN object_information_requests THEN
      NEXT p_object^.applicable_file_permit IN p_object_information;
      IF p_object^.applicable_file_permit = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;

      p_object^.applicable_file_permit^.permit_type := pfc$indirect_permit;
      p_object^.applicable_file_permit^.group := permit_entry.group;
      p_object^.applicable_file_permit^.usage_permissions := permit_entry.usage_permissions;
      p_object^.applicable_file_permit^.share_requirements := permit_entry.share_requirements;
      p_object^.applicable_file_permit^.application_info := permit_entry.application_info;
    IFEND;

    IF fsc$goi_file_info IN object_information_requests THEN
      NEXT p_file_information IN p_object_information;
      IF p_file_information = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;

      p_file_information^.account := p_physical_object^.object_entry.charge_id.account;

      IF authority.ownership = $pft$ownership [] THEN
        p_file_information^.logging_selection := NIL;
      ELSE
        NEXT p_logging_selection IN p_object_information;
        IF p_logging_selection = NIL THEN
          osp$set_status_condition (pfe$info_full, status);
          RETURN;
        IFEND;

        p_logging_selection^ := p_physical_object^.object_entry.logging_selection;
        p_file_information^.logging_selection := p_logging_selection;
      IFEND;

      p_file_information^.project := p_physical_object^.object_entry.charge_id.project;
      p_object^.file_information := p_file_information;
    IFEND;

    IF (fsc$goi_file_log IN object_information_requests) AND (authority.ownership <> $pft$ownership []) THEN
      pfp$build_log_list_pointer (p_physical_object^.object_entry.log_list_locator, p_catalog_file,
            p_log_list);

      IF p_log_list <> NIL THEN
        log_count := 0;
        FOR log_index := 1 TO UPPERBOUND (p_log_list^) DO
          IF p_log_list^ [log_index].log_entry.entry_type = pfc$normal_log_entry THEN
            log_count := log_count + 1;
          IFEND;
        FOREND;

        NEXT p_object^.file_log: [1 .. log_count] IN p_object_information;
        IF p_object^.file_log = NIL THEN
          osp$set_status_condition (pfe$info_full, status);
          RETURN;
        IFEND;

        log_count := 0;
        FOR log_index := 1 TO UPPERBOUND (p_log_list^) DO
          IF p_log_list^ [log_index].log_entry.entry_type = pfc$normal_log_entry THEN
            p_log_entry := ^p_log_list^ [log_index].log_entry;
            log_count := log_count + 1;
            p_object^.file_log^ [log_count].user_id := p_log_entry^.user_id;
            p_object^.file_log^ [log_count].access_date_time := p_log_entry^.access_date_time;
            p_object^.file_log^ [log_count].access_count := p_log_entry^.access_count;
            p_object^.file_log^ [log_count].last_cycle := p_log_entry^.last_cycle;
          IFEND;
        FOREND;
      IFEND;
    IFEND;

    IF fsc$goi_file_permits IN object_information_requests THEN
      get_permits (authority, p_physical_object^.object_entry.permit_list_locator, p_catalog_file, p_object,
            p_object_information, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
    IFEND;

    IF authority.ownership <> $pft$ownership [] THEN
       p_object^.password := p_physical_object^.object_entry.password;
    ELSE
       p_object^.password := osc$null_name;
    IFEND;

    IF (NOT unknown_cycle) AND ((fsc$goi_cycle_object_list IN object_information_requests) OR
          (object_information_requests * pfv$cycle_info_requests <> $fst$goi_object_info_requests [])) THEN
      get_cycle_list_information (family_location, binary_mainframe_id, path, object_information_requests,
            authority, p_physical_object, p_catalog_file, password_selector, validation_ring,
            p_physical_cycle, p_object, p_object_information, status);
    ELSE
      status.normal := TRUE;
    IFEND;
  PROCEND get_file_object_information;

?? TITLE := '  get_object_condition', EJECT ??

  PROCEDURE get_object_condition
    (    catalog_object: boolean;
         served_family: boolean;
         p_served_family_locator: ^pft$served_family_locator;
         p_fmd: ^dmt$stored_fmd;
     VAR device_info: fst$mass_storage_device_info;
     VAR p_object_information: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      p_unique_volume_list: ^pft$unique_volume_list;

    status.normal := TRUE;

    device_info.object_condition := fsc$null_file_access_condition;
    IF device_info.volume_list <> NIL THEN
      NEXT device_info.volume_condition_list: [LOWERBOUND (device_info.volume_list^) ..
            UPPERBOUND (device_info.volume_list^)] IN p_object_information;
      IF device_info.volume_condition_list <> NIL THEN
        IF p_fmd <> NIL THEN
          PUSH p_unique_volume_list: [1 .. UPPERBOUND (device_info.volume_list^)];
          dmp$get_unique_fmd_volume_list (p_fmd, p_unique_volume_list, status);
          IF status.normal THEN
            IF served_family THEN
              pfp$r2_df_client_get_vol_cl (p_served_family_locator^, p_unique_volume_list^,
                    device_info.volume_condition_list^, status);
            ELSE
              pfp$r2_get_vol_condition_list (p_unique_volume_list^, device_info.volume_condition_list^);
            IFEND;
            IF status.normal THEN
              device_info.object_condition := volume_list_condition
                    (catalog_object, device_info.volume_condition_list^);
            IFEND;
          IFEND;
        IFEND;
      ELSE
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;
    ELSE
      device_info.volume_condition_list := NIL;
    IFEND;
  PROCEND get_object_condition;

?? TITLE := '  get_object_information', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to get the requested information about the
{   specified catalog, file, or cycle object.

  PROCEDURE get_object_information
    (    family_location: pft$family_location;
         binary_mainframe_id: pmt$binary_mainframe_id;
         path: pft$complete_path;
         information_request: fst$goi_information_request;
         authority: pft$authority;
         permit_entry: pft$permit_entry;
         p_physical_object: {input^} ^pft$physical_object;
         unknown_cycle: boolean;
         password_selector: pft$password_selector;
         validation_ring: ost$valid_ring;
         p_subject_permit_id_list: {i/o^} ^subject_permit_id_list;
         p_physical_cycle: {i/o^} ^pft$physical_cycle,
         p_object_info: {output^} ^fst$goi_object_information;
     VAR catalog_locator: {i/o} pft$catalog_locator;
     VAR permitted_to_object: {i/o} boolean;
     VAR p_object_information: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      device_class: rmt$device_class,
      p_object: ^fst$goi_object,
      password_status: ost$status;

    NEXT p_object IN p_object_information;
    IF p_object = NIL THEN
      osp$set_status_condition (pfe$info_full, status);
      RETURN;
    IFEND;

    IF p_physical_object^.object_entry.object_type = pfc$catalog_object THEN
      initialize_catalog_object (p_physical_object^.object_entry, p_object);

      IF (password_selector.password_specified = pfc$specific_password_option) AND
            (password_selector.password <> osc$null_name) THEN
        osp$set_status_condition (pfe$catalogs_have_no_password, status);
        RETURN;
      IFEND;

      get_catalog_object_information (family_location, binary_mainframe_id, path, information_request,
            {current_depth} 1, authority, permit_entry, p_physical_object, password_selector, validation_ring,
            p_subject_permit_id_list, p_object, catalog_locator, permitted_to_object, p_object_information,
            status);
    ELSEIF information_request.object_information_requests * pfv$file_info_requests <>
          $fst$goi_object_info_requests [] THEN
      initialize_file_object (p_physical_object^.object_entry.external_object_name, p_object);
      get_file_object_information (family_location, binary_mainframe_id, path,
            information_request.object_information_requests, authority, permit_entry, p_physical_object,
            catalog_locator.p_catalog_file, unknown_cycle, password_selector, validation_ring,
            p_physical_cycle, p_object, p_object_information, status);
    ELSEIF p_physical_cycle = NIL THEN
      status.normal := TRUE;
      RETURN;
    ELSE
      IF information_request.object_information_requests * protected_info_requests =
            $fst$goi_object_info_requests [] THEN
        password_status.normal := TRUE;
      ELSEIF password_selector.password_specified = pfc$default_password_option THEN
        pfp$validate_password (path, authority, osc$null_name, p_physical_object, password_status);
      ELSE
        pfp$validate_password (path, authority, password_selector.password, p_physical_object,
              password_status);
      IFEND;

      IF p_physical_cycle^.cycle_entry.device_information.device_class_defined THEN
        pfp$convert_device_class_to_rm (p_physical_cycle^.cycle_entry.device_information.device_class,
              device_class);
      ELSE
        device_class := rmc$mass_storage_device;
      IFEND;

      initialize_cycle_object (p_physical_cycle^.cycle_entry.cycle_number,
            p_physical_cycle^.cycle_entry.global_file_name, device_class,
            {validation_error} NOT password_status.normal, p_object);

      IF information_request.object_information_requests * pfv$cycle_info_requests -
            $fst$goi_object_info_requests [fsc$goi_cycle_identity] = $fst$goi_object_info_requests [] THEN
        status.normal := TRUE;
      ELSE
        get_cycle_object_information (family_location, binary_mainframe_id, path,
              information_request.object_information_requests, authority, p_physical_object, validation_ring,
              p_physical_cycle, catalog_locator.p_catalog_file, p_object, p_object_information, status);
        IF (NOT password_status.normal) AND (status.normal OR (status.condition = pfe$invalid_ring_access) OR
              (status.condition = ame$damaged_file_attributes)) THEN
          status := password_status;
        IFEND;
      IFEND;
    IFEND;

    IF permitted_to_object THEN
      p_object_info^.object := p_object;
    IFEND;
  PROCEND get_object_information;

?? TITLE := '  get_object_list_information', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to access the specified catalog and to get
{   the requested information about the files and/or subcatalogs within the
{   specified catalog.

  PROCEDURE get_object_list_information
    (    family_location: pft$family_location;
         binary_mainframe_id: pmt$binary_mainframe_id;
         path: pft$complete_path;
         information_request: fst$goi_information_request;
         current_depth: fst$path_element_index;
         authority: pft$authority;
         permit_entry: pft$permit_entry;
         password_selector: pft$password_selector;
         validation_ring: ost$valid_ring;
         p_subject_permit_id_list: {i/o^} ^subject_permit_id_list;
         p_object: {output^} ^fst$goi_object;
     VAR catalog_locator: {i/o} pft$catalog_locator;
     VAR permitted_to_catalog: {i/o} boolean;
     VAR p_object_information: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      all_subjects_are_permitted: boolean,
      extracted_permit_entry: pft$permit_entry,
      internal_name: pft$internal_name,
      local_status: ost$status,
      max_object_name_index: pft$object_count,
      max_sorted_object_index: pft$object_count,
      new_catalog_locator: pft$catalog_locator,
      new_permit_entry: pft$permit_entry,
      object_accessed: boolean,
      object_count: pft$object_count,
      object_index: pft$object_index,
      object_information_requests: fst$goi_object_info_requests,
      object_name_index: pft$object_index,
      p_internal_path: ^pft$internal_path,
      p_local_object_list: ^pft$object_list,
      p_new_path: ^pft$complete_path,
      p_object_list: ^pft$object_list,
      p_object_name_list: ^pft$object_name_list,
      p_objects: ^fst$goi_object_list,
      p_permit_list: ^pft$permit_list,
      p_subject_permit_id_lists: ^array [1 .. * ] of ^subject_permit_id_list,
      parent_charge_id: pft$charge_id,
      path_index: pft$file_path_index,
      sorted_object_index: pft$object_index;

    object_information_requests := information_request.object_information_requests;

    p_object_list := catalog_locator.object_list_descriptor.p_object_list;
    object_count := 0;
    PUSH p_local_object_list: [1 .. UPPERBOUND (p_object_list^)];
    PUSH p_subject_permit_id_lists: [1 .. UPPERBOUND (p_object_list^)];

    IF catalog_locator.object_list_descriptor.sorted_object_count = 0 THEN
      PUSH p_object_name_list: [1 .. UPPERBOUND (p_object_list^)];
    ELSE
      PUSH p_object_name_list: [1 .. UPPERBOUND (p_object_list^) -
            catalog_locator.object_list_descriptor.sorted_object_count];
    IFEND;

    pfp$get_sorted_object_name_list (catalog_locator.object_list_descriptor, p_object_name_list,
          max_object_name_index);
    max_sorted_object_index := catalog_locator.object_list_descriptor.sorted_object_count;
    sorted_object_index := 1;
    object_name_index := 1;

    WHILE (sorted_object_index <= max_sorted_object_index) OR (object_name_index <= max_object_name_index) DO
      IF object_name_index > max_object_name_index THEN
        object_index := sorted_object_index;
        sorted_object_index := sorted_object_index + 1;
      ELSEIF sorted_object_index > max_sorted_object_index THEN
        object_index := p_object_name_list^[object_name_index].object_index;
        object_name_index := object_name_index + 1;
      ELSEIF p_object_list^[sorted_object_index].object_entry.external_object_name >
            p_object_name_list^[object_name_index].object_name THEN
        object_index := p_object_name_list^[object_name_index].object_index;
        object_name_index := object_name_index + 1;
      ELSE
        object_index := sorted_object_index;
        sorted_object_index := sorted_object_index + 1;
      IFEND;

      IF ((p_object_list^ [object_index].object_entry.object_type = pfc$file_object) AND
            ((fsc$goi_file_object_list IN object_information_requests) OR
            (((information_request.catalog_depth.depth_specification = fsc$entire_subtree) OR
            (current_depth <= information_request.catalog_depth.depth)) AND
            (object_information_requests - pfv$catalog_info_requests <> $fst$goi_object_info_requests []))))
            OR ((p_object_list^ [object_index].object_entry.object_type = pfc$catalog_object) AND
            ((fsc$goi_catalog_object_list IN object_information_requests) OR
            (((information_request.catalog_depth.depth_specification = fsc$entire_subtree) OR
            (current_depth < information_request.catalog_depth.depth)) AND
            (object_information_requests * pfv$catalog_info_requests <> $fst$goi_object_info_requests [])) OR
            NOT permitted_to_catalog)) THEN
        pfp$build_permit_list_pointer (p_object_list^ [object_index].object_entry.permit_list_locator,
              catalog_locator.p_catalog_file, p_permit_list);
        pfp$extract_permit_entry (p_permit_list, authority, extracted_permit_entry);
        pfp$reduce_permits (permit_entry, extracted_permit_entry, new_permit_entry);
        pfp$form_administrator_permit (authority, new_permit_entry);

        IF p_subject_permit_id_list <> NIL THEN
          PUSH p_subject_permit_id_lists^ [object_count + 1]: [1 .. UPPERBOUND (p_subject_permit_id_list^)];
          validate_subject_permits (p_permit_list, p_subject_permit_id_list,
                p_subject_permit_id_lists^ [object_count + 1], all_subjects_are_permitted);
        IFEND;

        IF ((authority.ownership <> $pft$ownership []) OR
              ((new_permit_entry.entry_type = pfc$normal_permit_entry) AND
              (new_permit_entry.usage_permissions <> $pft$permit_selections [])) OR
              ((p_object_list^ [object_index].object_entry.object_type = pfc$catalog_object) AND
              NOT osv$catalog_name_security)) AND
              ((p_subject_permit_id_list = NIL) OR all_subjects_are_permitted) THEN
          object_count := object_count + 1;
          p_local_object_list^ [object_count] := p_object_list^ [object_index];
        IFEND;
      IFEND;
    WHILEND;

    IF object_count = 0 THEN
      status.normal := TRUE;
      RETURN;
    ELSEIF NOT permitted_to_catalog THEN
      permitted_to_catalog := TRUE;
      IF NOT (fsc$goi_catalog_object_list IN object_information_requests) AND
            (((information_request.catalog_depth.depth_specification = fsc$specific_depth) AND
            (information_request.catalog_depth.depth <= current_depth)) OR
            (object_information_requests * pfv$catalog_info_requests = $fst$goi_object_info_requests [])) THEN
        status.normal := TRUE;
        RETURN;
      IFEND;
    IFEND;

    NEXT p_objects: [1 .. object_count] IN p_object_information;
    IF p_objects = NIL THEN
      osp$set_status_condition (pfe$info_full, status);
      RETURN;
    IFEND;

    status.normal := TRUE;

    PUSH p_new_path: [1 .. UPPERBOUND (path) + 1];
    FOR path_index := 1 TO UPPERBOUND (path) DO
      p_new_path^ [path_index] := path [path_index];
    FOREND;

    FOR object_index := 1 TO object_count DO
      IF p_local_object_list^ [object_index].object_entry.object_type = pfc$file_object THEN
        initialize_file_object (p_local_object_list^ [object_index].object_entry.external_object_name,
              ^p_objects^ [object_index]);

        IF (status.normal OR (status.condition <> pfe$info_full)) AND
              ((information_request.catalog_depth.depth_specification = fsc$entire_subtree) OR
              (current_depth <= information_request.catalog_depth.depth)) AND
              (object_information_requests - pfv$catalog_info_requests <> $fst$goi_object_info_requests [])
              THEN
          p_new_path^ [path_index + 1] :=
                p_local_object_list^ [object_index].object_entry.external_object_name;
          get_file_object_information (family_location, binary_mainframe_id, p_new_path^,
                object_information_requests, authority, new_permit_entry,
                ^p_local_object_list^ [object_index], catalog_locator.p_catalog_file, {unknown_cycle} FALSE,
                password_selector, validation_ring, {p_physical_cycle} NIL, ^p_objects^ [object_index],
                p_object_information, local_status);
          IF (NOT local_status.normal) AND (status.normal OR (local_status.condition = pfe$info_full)) THEN
            status := local_status;
          IFEND;
        IFEND;
      ELSE
        initialize_catalog_object (p_local_object_list^ [object_index].object_entry,
              ^p_objects^ [object_index]);
      IFEND;
    FOREND;

{   IF (status.normal OR (status.condition <> pfe$info_full)) AND
{         ((information_request.catalog_depth.depth_specification = fsc$entire_subtree) OR
{         (current_depth < information_request.catalog_depth.depth)) AND
{         (object_information_requests * pfv$catalog_info_requests <> $fst$goi_object_info_requests []) THEN
{     new_catalog_locator := catalog_locator;
{     object_accessed := TRUE;
{
{   /get_catalog_object_info/
{     FOR object_index := 1 TO object_count DO
{       IF p_local_object_list^ [object_index].object_entry.object_type = pfc$catalog_object THEN
{         p_new_path^ [path_index + 1] :=
{               p_local_object_list^ [object_index].object_entry.external_object_name;
{
{         IF new_catalog_locator <> catalog_locator THEN
{           {
{           { Because each subcatalog is attached when it is processed, the
{           { parent catalog needs to be reattached to process all but the
{           { first subcatalog in the list.
{           {
{           IF object_accessed THEN
{             pfp$return_catalog (new_catalog_locator, local_status);
{             IF NOT local_status.normal THEN
{               IF status.normal THEN
{                 status := local_status;
{               IFEND;
{               RETURN;
{             IFEND;
{           IFEND;
{
{           PUSH p_internal_path: [1 .. UPPERBOUND (p_new_path)];
{           pfp$access_object (p_new_path^, pfc$read_access, authority, valid_objects, parent_charge_id,
{                 new_catalog_locator, p_local_object_list^ [object_index], p_internal_path, new_permit_entry,
{                 local_status);
{           object_accessed := local_status.normal;
{           IF NOT local_status.normal THEN
{             IF status.normal THEN
{               status := local_status;
{             IFEND;
{             CYCLE /get_catalog_object_info/;
{           IFEND;
{
{           catalog_locator := new_catalog_locator;
{           pfp$form_administrator_permit (authority, new_permit_entry);
{         IFEND;
{
{         get_catalog_object_information (family_location, binary_mainframe_id, p_new_path^,
{               information_request, (current_depth + 1), authority, new_permit_entry,
{               ^p_local_object_list^ [object_index], password_selector, validation_ring,
{               p_subject_permit_id_lists^ [object_index], ^p_objects^ [object_index], new_catalog_locator,
{               permitted_to_catalog, p_object_information, local_status);
{         IF NOT local_status.normal THEN
{           IF local_status.condition = pfe$info_full THEN
{             status := local_status;
{             EXIT /get_catalog_object_info/;
{           ELSEIF status.normal THEN
{             status := local_status;
{           IFEND;
{         IFEND;
{       IFEND;
{     FOREND /get_catalog_object_info/;
{   IFEND;

    p_object^.subcatalog_and_file_object_list := p_objects;
  PROCEND get_object_list_information;

?? TITLE := '  get_permits', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to get permits for a catalog or file.

  PROCEDURE get_permits
    (    authority: pft$authority;
         permit_list_locator: pft$permit_list_locator;
         p_catalog_file: {input^} ^pft$catalog_file;
         p_object: {i^/o^} ^fst$goi_object;
     VAR p_object_information: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      p_permit_entry: ^pft$permit_entry,
      p_permit_list: ^pft$permit_list,
      p_permits: ^pft$permit_array,
      permit_count: pft$permit_count,
      permit_entry: pft$permit_entry,
      permit_index: pft$permit_index;

    pfp$build_permit_list_pointer (permit_list_locator, p_catalog_file, p_permit_list);

    IF p_permit_list <> NIL THEN
      IF authority.ownership = $pft$ownership [] THEN
        p_permits := NIL;
      ELSE
        permit_count := 0;
        FOR permit_index := 1 TO UPPERBOUND (p_permit_list^) DO
          IF p_permit_list^ [permit_index].permit_entry.entry_type = pfc$normal_permit_entry THEN
            permit_count := permit_count + 1;
          IFEND;
        FOREND;

        IF permit_count > 0 THEN
          NEXT p_permits: [1 .. permit_count] IN p_object_information;
          IF p_permits = NIL THEN
            osp$set_status_condition (pfe$info_full, status);
            RETURN;
          IFEND;

          permit_count := 0;
          FOR permit_index := 1 TO UPPERBOUND (p_permit_list^) DO
            IF p_permit_list^ [permit_index].permit_entry.entry_type = pfc$normal_permit_entry THEN
              permit_count := permit_count + 1;
              p_permit_entry := ^p_permit_list^ [permit_index].permit_entry;
              p_permits^ [permit_count].permit_type := pfc$direct_permit;
              p_permits^ [permit_count].group := p_permit_entry^.group;
              p_permits^ [permit_count].usage_permissions := p_permit_entry^.usage_permissions;
              p_permits^ [permit_count].share_requirements := p_permit_entry^.share_requirements;
              p_permits^ [permit_count].application_info := p_permit_entry^.application_info;
            IFEND;
          FOREND;
        ELSE
          p_permits := NIL;
        IFEND;
      IFEND;

      IF p_object^.object_type = fsc$goi_catalog_object THEN
        p_object^.catalog_permits := p_permits;
      ELSEIF p_object^.object_type = fsc$goi_file_object THEN
        p_object^.file_permits := p_permits;
      IFEND;
    IFEND;

    status.normal := TRUE;
  PROCEND get_permits;

?? TITLE := '  get_protected_info_from_cd', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to get the requested, password protected
{   information about a cycle which is attached within the job.

  PROCEDURE get_protected_info_from_cd
    (    served_family: boolean;
         served_family_locator: pft$served_family_locator;
         evaluated_file_reference: fst$evaluated_file_reference;
         object_information_requests: fst$goi_object_info_requests;
         p_cycle_description: {input^} ^fmt$cycle_description;
         password_selector: pft$password_selector;
         validation_ring: ost$valid_ring;
         p_object: {output^} ^fst$goi_object;
     VAR p_object_information: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      fs_path_size: fst$path_size,
      label_size: ost$non_negative_integers,
      p_complete_path: ^pft$complete_path,
      p_fs_path: ^fst$path,
      p_path: ^pft$path,
      p_static_label_header: ^fmt$static_label_header,
      ring_attributes: amt$ring_attributes;

    IF (password_selector.password_specified = pfc$specific_password_option) AND
          (p_cycle_description^.password_protected OR (password_selector.password <> osc$null_name)) THEN
      IF served_family THEN
        PUSH p_path: [1 .. evaluated_file_reference.number_of_path_elements];
        pfp$convert_fs_to_pft$path (evaluated_file_reference, p_path^);
        pfp$r2_df_client_validate_pw (served_family_locator, p_path^, password_selector.password, status);
        p_object^.validation_error := NOT status.normal;
      ELSE
        PUSH p_complete_path: [1 .. evaluated_file_reference.number_of_path_elements + 1];
        pfp$convert_fs_to_complete_path (evaluated_file_reference, p_complete_path, status);
        IF status.normal THEN
          pfp$r2_validate_password (p_complete_path^, password_selector.password, status);
          p_object^.validation_error := NOT status.normal;
        IFEND;
      IFEND;
      IF NOT status.normal THEN
        RETURN;
      IFEND;
    IFEND;

    IF object_information_requests * protected_info_requests <> $fst$goi_object_info_requests [] THEN
      IF p_cycle_description^.system_file_label.file_previously_opened THEN
        fmp$get_label_header_info (^p_cycle_description^.system_file_label, ring_attributes, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;

        IF validation_ring > ring_attributes.r3 THEN
          p_object^.validation_error := TRUE;
          PUSH p_fs_path;
          clp$convert_file_ref_to_string (evaluated_file_reference, {include_open_position} FALSE, p_fs_path^,
                fs_path_size, status);
          IF status.normal THEN
            osp$set_status_abnormal (pfc$permanent_file_manager_id, pfe$invalid_ring_access,
                  p_fs_path^ (1, fs_path_size), status);
          ELSE
            osp$set_status_condition (pfe$invalid_ring_access, status);
          IFEND;
          RETURN;
        IFEND;
      IFEND;

      IF fsc$goi_job_environment_info IN object_information_requests THEN
        NEXT p_object^.job_environment_information IN p_object_information;
        IF p_object^.job_environment_information = NIL THEN
          osp$set_status_condition (pfe$info_full, status);
          RETURN;
        IFEND;

        fmp$setup_job_environment_info (p_cycle_description, {path_handle_p} NIL,
              p_object^.job_environment_information, p_object_information);
      IFEND;

      IF fsc$goi_file_label IN object_information_requests THEN
        IF NOT p_cycle_description^.system_file_label.file_previously_opened AND
              (p_cycle_description^.static_setfa_entries <> NIL) THEN
          p_object^.file_label := p_cycle_description^.system_file_label.static_label;
          fmp$merge_setfa_entries (p_cycle_description^.static_setfa_entries, p_object, p_object_information,
                status);
          IF NOT status.normal THEN
            p_object^.file_label := NIL;
          IFEND;
        ELSEIF p_cycle_description^.system_file_label.static_label <> NIL THEN
          label_size := #SIZE (p_cycle_description^.system_file_label.static_label^);
          NEXT p_object^.file_label: [[REP label_size OF cell]] IN p_object_information;
          IF p_object^.file_label = NIL THEN
            osp$set_status_condition (pfe$info_full, status);
            RETURN;
          IFEND;

          i#move (p_cycle_description^.system_file_label.static_label, p_object^.file_label, label_size);
          status.normal := TRUE;
        ELSE
          label_size := #SIZE (fmt$static_label_header);
          NEXT p_object^.file_label: [[REP label_size OF cell]] IN p_object_information;
          IF p_object^.file_label = NIL THEN
            osp$set_status_condition (pfe$info_full, status);
            RETURN;
          IFEND;

          i#move (^fmv$static_label_header, p_object^.file_label, label_size);
          IF NOT p_cycle_description^.system_file_label.file_previously_opened THEN
            RESET p_object^.file_label;
            NEXT p_static_label_header IN p_object^.file_label;
            IF p_static_label_header <> NIL THEN
              p_static_label_header^.file_previously_opened := FALSE;
            IFEND;
          IFEND;
          status.normal := TRUE;
        IFEND;
      ELSE
        status.normal := TRUE;
      IFEND;
    ELSE
      status.normal := TRUE;
    IFEND;
  PROCEND get_protected_info_from_cd;

?? TITLE := '  get_tape_device_info_from_fmd', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to get tape device information from an
{   fmd.

  PROCEDURE get_tape_device_info_from_fmd
    (    p_fmd: {input^} pft$p_fmd;
         p_device_information: {output^} ^fst$device_information;
     VAR p_object_information: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      number_of_volumes: 0 .. amc$max_vol_number,
      p_pf_volume_list: ^pft$volume_list,
      p_rm_volume_list: ^rmt$volume_list,
      p_volume_list: ^rmt$volume_list,
      removable_media_req_info: fmt$removable_media_req_info;

    pfp$get_rem_media_req_info (p_fmd, ^removable_media_req_info, number_of_volumes, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    p_device_information^.magnetic_tape_device_info.density := removable_media_req_info.density;
    p_device_information^.magnetic_tape_device_info.removable_media_group :=
          removable_media_req_info.removable_media_group;
    p_device_information^.magnetic_tape_device_info.volume_overflow_allowed :=
          removable_media_req_info.volume_overflow_allowed;

    IF number_of_volumes > 0 THEN
      NEXT p_volume_list: [1 .. number_of_volumes] IN p_object_information;
      IF p_volume_list <> NIL THEN
        pfp$get_rem_media_volume_list (p_fmd, p_volume_list, status);
      ELSE
        p_volume_list := NIL;
      IFEND;
      IF NOT status.normal THEN
        RETURN;
      IFEND;
    ELSE
      p_volume_list := NIL;
    IFEND;

    p_device_information^.magnetic_tape_device_info.volume_list := p_volume_list;

  PROCEND get_tape_device_info_from_fmd;

?? TITLE := '  [INLINE] initialize_catalog_object', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to initialize catalog object information.

  PROCEDURE [INLINE] initialize_catalog_object
    (    object_entry: pft$object_entry;
         p_object: {output^} ^fst$goi_object);

    p_object^.object_type := fsc$goi_catalog_object;
    p_object^.catalog_name := object_entry.external_object_name;
    IF object_entry.catalog_object_locator.catalog_type = pfc$external_catalog THEN
      p_object^.catalog_global_file_name := object_entry.catalog_object_locator.global_file_name;
    ELSE
      p_object^.catalog_global_file_name := pfv$null_unique_name;
    IFEND;
    p_object^.applicable_catalog_permit := NIL;
    p_object^.catalog_device_information := NIL;
    p_object^.catalog_information := NIL;
    p_object^.catalog_permits := NIL;
    p_object^.catalog_size := NIL;
    p_object^.subcatalog_and_file_object_list := NIL;
  PROCEND initialize_catalog_object;

?? TITLE := '  [INLINE] initialize_cycle_object', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to initialize cycle object information.

  PROCEDURE [INLINE] initialize_cycle_object
    (    cycle_number: fst$cycle_number;
         global_file_name: ost$binary_unique_name;
         device_class: rmt$device_class;
         validation_error: boolean;
         p_object: {output^} ^fst$goi_object);

    p_object^.object_type := fsc$goi_cycle_object;
    p_object^.cycle_number := cycle_number;
    p_object^.cycle_global_file_name := global_file_name;
    p_object^.cycle_device_class := device_class;
    p_object^.archive_information_list := NIL;
    p_object^.cycle_device_information := NIL;
    p_object^.cycle_information := NIL;
    p_object^.cycle_size := NIL;
    p_object^.validation_error := validation_error;
    p_object^.file_label := NIL;
    p_object^.job_environment_information := NIL;
  PROCEND initialize_cycle_object;

?? TITLE := '  [INLINE] initialize_file_object', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to initialize file object information.

  PROCEDURE [INLINE] initialize_file_object
    (    file_name: pft$name;
         p_object: {output^} ^fst$goi_object);

    p_object^.object_type := fsc$goi_file_object;
    p_object^.file_name := file_name;
    p_object^.applicable_file_permit := NIL;
    p_object^.file_information := NIL;
    p_object^.file_log := NIL;
    p_object^.file_permits := NIL;
    p_object^.password := osc$null_name;
    p_object^.cycle_object_list := NIL;
  PROCEND initialize_file_object;

?? TITLE := '  move_catalog_object_information', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to move catalog information from the local
{   sequence to the caller supplied sequence.

  PROCEDURE move_catalog_object_information
    (    local_catalog_object: fst$goi_object;
     VAR catalog_object: fst$goi_object;
     VAR p_object_information: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      object_index: ost$positive_integers;

    catalog_object.catalog_name := local_catalog_object.catalog_name;
    catalog_object.catalog_global_file_name := local_catalog_object.catalog_global_file_name;

    IF local_catalog_object.applicable_catalog_permit = NIL THEN
      catalog_object.applicable_catalog_permit := NIL;
    ELSE
      NEXT catalog_object.applicable_catalog_permit IN p_object_information;
      IF catalog_object.applicable_catalog_permit = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;

      catalog_object.applicable_catalog_permit^ := local_catalog_object.applicable_catalog_permit^;
    IFEND;

    IF local_catalog_object.catalog_device_information = NIL THEN
      catalog_object.catalog_device_information := NIL;
    ELSE
      NEXT catalog_object.catalog_device_information IN p_object_information;
      IF catalog_object.catalog_device_information = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;

      catalog_object.catalog_device_information^.mass_storage_device_info.bytes_allocated :=
            local_catalog_object.catalog_device_information^.mass_storage_device_info.bytes_allocated;
      catalog_object.catalog_device_information^.mass_storage_device_info.object_condition :=
            local_catalog_object.catalog_device_information^.mass_storage_device_info.object_condition;
      catalog_object.catalog_device_information^.mass_storage_device_info.shared_queue :=
            local_catalog_object.catalog_device_information^.mass_storage_device_info.shared_queue;
      catalog_object.catalog_device_information^.mass_storage_device_info.resides_online :=
            local_catalog_object.catalog_device_information^.mass_storage_device_info.resides_online;

      IF catalog_object.catalog_device_information^.mass_storage_device_info.resides_online THEN
        catalog_object.catalog_device_information^.mass_storage_device_info.allocation_unit_size :=
              local_catalog_object.catalog_device_information^.mass_storage_device_info.allocation_unit_size;
        catalog_object.catalog_device_information^.mass_storage_device_info.initial_volume :=
              local_catalog_object.catalog_device_information^.mass_storage_device_info.initial_volume;
        catalog_object.catalog_device_information^.mass_storage_device_info.mass_storage_class :=
              local_catalog_object.catalog_device_information^.mass_storage_device_info.mass_storage_class;
        catalog_object.catalog_device_information^.mass_storage_device_info.transfer_size :=
              local_catalog_object.catalog_device_information^.mass_storage_device_info.transfer_size;

        IF local_catalog_object.catalog_device_information^.mass_storage_device_info.volume_list = NIL THEN
          catalog_object.catalog_device_information^.mass_storage_device_info.volume_list := NIL;
        ELSE
          NEXT catalog_object.catalog_device_information^.mass_storage_device_info.volume_list:
                [1 .. UPPERBOUND (local_catalog_object.catalog_device_information^.mass_storage_device_info.
                volume_list^)] IN p_object_information;
          IF catalog_object.catalog_device_information^.mass_storage_device_info.volume_list = NIL THEN
            osp$set_status_condition (pfe$info_full, status);
            RETURN;
          IFEND;

          catalog_object.catalog_device_information^.mass_storage_device_info.volume_list^ :=
                local_catalog_object.catalog_device_information^.mass_storage_device_info.volume_list^;
        IFEND;

        IF local_catalog_object.catalog_device_information^.mass_storage_device_info.volume_condition_list =
              NIL THEN
          catalog_object.catalog_device_information^.mass_storage_device_info.volume_condition_list := NIL;
        ELSE
          NEXT catalog_object.catalog_device_information^.mass_storage_device_info.volume_condition_list:
                [1 .. UPPERBOUND (local_catalog_object.catalog_device_information^.mass_storage_device_info.
                volume_condition_list^)] IN p_object_information;
          IF catalog_object.catalog_device_information^.mass_storage_device_info.volume_condition_list = NIL
              THEN
            osp$set_status_condition (pfe$info_full, status);
            RETURN;
          IFEND;

          catalog_object.catalog_device_information^.mass_storage_device_info.volume_condition_list^ :=
                local_catalog_object.catalog_device_information^.mass_storage_device_info.
                volume_condition_list^;
        IFEND;

        catalog_object.catalog_device_information^.mass_storage_device_info.volume_overflow_allowed :=
              local_catalog_object.catalog_device_information^.mass_storage_device_info.
              volume_overflow_allowed;
      IFEND;
    IFEND;

    IF local_catalog_object.catalog_information = NIL THEN
      catalog_object.catalog_information := NIL;
    ELSE
      NEXT catalog_object.catalog_information IN p_object_information;
      IF catalog_object.catalog_information = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;

      catalog_object.catalog_information^ := local_catalog_object.catalog_information^;
    IFEND;

    IF local_catalog_object.catalog_permits = NIL THEN
      catalog_object.catalog_permits := NIL;
    ELSE
      NEXT catalog_object.catalog_permits: [1 .. UPPERBOUND (local_catalog_object.catalog_permits^)]
            IN p_object_information;
      IF catalog_object.catalog_permits = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;

      catalog_object.catalog_permits^ := local_catalog_object.catalog_permits^;
    IFEND;

    IF local_catalog_object.catalog_size = NIL THEN
      catalog_object.catalog_size := NIL;
    ELSE
      NEXT catalog_object.catalog_size IN p_object_information;
      IF catalog_object.catalog_size = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;

      catalog_object.catalog_size^ := local_catalog_object.catalog_size^;
    IFEND;

    IF local_catalog_object.subcatalog_and_file_object_list = NIL THEN
      catalog_object.subcatalog_and_file_object_list := NIL;
    ELSE
      NEXT catalog_object.subcatalog_and_file_object_list:
            [1 .. UPPERBOUND (local_catalog_object.subcatalog_and_file_object_list^)] IN p_object_information;
      IF catalog_object.subcatalog_and_file_object_list = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;

      FOR object_index := 1 TO UPPERBOUND (catalog_object.subcatalog_and_file_object_list^) DO
        catalog_object.subcatalog_and_file_object_list^ [object_index].object_type :=
              local_catalog_object.subcatalog_and_file_object_list^ [object_index].object_type;

        CASE catalog_object.subcatalog_and_file_object_list^ [object_index].object_type OF
        = fsc$goi_catalog_object =
          move_catalog_object_information
                (local_catalog_object.subcatalog_and_file_object_list^ [object_index],
                catalog_object.subcatalog_and_file_object_list^ [object_index], p_object_information, status);
        = fsc$goi_file_object =
          move_file_object_information (local_catalog_object.subcatalog_and_file_object_list^ [object_index],
                catalog_object.subcatalog_and_file_object_list^ [object_index], p_object_information, status);
        = fsc$goi_cycle_object =
          move_cycle_object_information (local_catalog_object.subcatalog_and_file_object_list^ [object_index],
                catalog_object.subcatalog_and_file_object_list^ [object_index], p_object_information, status);
        ELSE
          osp$set_status_abnormal (pfc$permanent_file_manager_id, pfe$pf_system_error,
                'Invalid object_type in move_catalog_object_information.', status);
        CASEND;
        IF NOT status.normal THEN
          RETURN;
        IFEND;
      FOREND;
    IFEND;

    status.normal := TRUE;
  PROCEND move_catalog_object_information;

?? TITLE := '  move_cycle_device_information', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to move cycle device information from the
{   local sequence to the caller supplied sequence.

  PROCEDURE move_cycle_device_information
    (    cycle_device_class: rmt$device_class;
         local_cycle_device_information: fst$device_information;
     VAR cycle_device_information: fst$device_information;
     VAR p_object_information: ^SEQ ( * );
     VAR status: ost$status);

    IF cycle_device_class = rmc$mass_storage_device THEN
      cycle_device_information.mass_storage_device_info.bytes_allocated :=
            local_cycle_device_information.mass_storage_device_info.bytes_allocated;
      cycle_device_information.mass_storage_device_info.object_condition :=
            local_cycle_device_information.mass_storage_device_info.object_condition;
      cycle_device_information.mass_storage_device_info.shared_queue :=
            local_cycle_device_information.mass_storage_device_info.shared_queue;
      cycle_device_information.mass_storage_device_info.resides_online :=
            local_cycle_device_information.mass_storage_device_info.resides_online;

      IF cycle_device_information.mass_storage_device_info.resides_online THEN
        cycle_device_information.mass_storage_device_info.allocation_unit_size :=
              local_cycle_device_information.mass_storage_device_info.allocation_unit_size;
        cycle_device_information.mass_storage_device_info.initial_volume :=
              local_cycle_device_information.mass_storage_device_info.initial_volume;
        cycle_device_information.mass_storage_device_info.mass_storage_class :=
              local_cycle_device_information.mass_storage_device_info.mass_storage_class;
        cycle_device_information.mass_storage_device_info.transfer_size :=
              local_cycle_device_information.mass_storage_device_info.transfer_size;

        IF local_cycle_device_information.mass_storage_device_info.volume_list = NIL THEN
          cycle_device_information.mass_storage_device_info.volume_list := NIL;
        ELSE
          NEXT cycle_device_information.mass_storage_device_info.volume_list:
                [1 .. UPPERBOUND (local_cycle_device_information.mass_storage_device_info.volume_list^)]
                IN p_object_information;
          IF cycle_device_information.mass_storage_device_info.volume_list = NIL THEN
            osp$set_status_condition (pfe$info_full, status);
            RETURN;
          IFEND;

          cycle_device_information.mass_storage_device_info.volume_list^ :=
                local_cycle_device_information.mass_storage_device_info.volume_list^;
        IFEND;

        IF local_cycle_device_information.mass_storage_device_info.volume_condition_list = NIL THEN
          cycle_device_information.mass_storage_device_info.volume_condition_list := NIL;
        ELSE
          NEXT cycle_device_information.mass_storage_device_info.volume_condition_list:
                [1 .. UPPERBOUND (local_cycle_device_information.mass_storage_device_info.
                volume_condition_list^)] IN p_object_information;
          IF cycle_device_information.mass_storage_device_info.volume_condition_list = NIL THEN
            osp$set_status_condition (pfe$info_full, status);
            RETURN;
          IFEND;

          cycle_device_information.mass_storage_device_info.volume_condition_list^ :=
                local_cycle_device_information.mass_storage_device_info.volume_condition_list^;
        IFEND;

        cycle_device_information.mass_storage_device_info.volume_overflow_allowed :=
              local_cycle_device_information.mass_storage_device_info.volume_overflow_allowed;
      IFEND;
    ELSEIF cycle_device_class = rmc$magnetic_tape_device THEN
      cycle_device_information.magnetic_tape_device_info.density :=
            local_cycle_device_information.magnetic_tape_device_info.density;
      cycle_device_information.magnetic_tape_device_info.removable_media_group :=
            local_cycle_device_information.magnetic_tape_device_info.removable_media_group;
      cycle_device_information.magnetic_tape_device_info.volume_overflow_allowed :=
            local_cycle_device_information.magnetic_tape_device_info.volume_overflow_allowed;

      IF local_cycle_device_information.magnetic_tape_device_info.volume_list = NIL THEN
        cycle_device_information.magnetic_tape_device_info.volume_list := NIL;
      ELSE
        NEXT cycle_device_information.magnetic_tape_device_info.volume_list:
              [LOWERBOUND (local_cycle_device_information.magnetic_tape_device_info.volume_list^) ..
              UPPERBOUND (local_cycle_device_information.magnetic_tape_device_info.volume_list^)]
              IN p_object_information;
        IF cycle_device_information.magnetic_tape_device_info.volume_list = NIL THEN
          osp$set_status_condition (pfe$info_full, status);
          RETURN;
        IFEND;
        cycle_device_information.magnetic_tape_device_info.volume_list^ :=
              local_cycle_device_information.magnetic_tape_device_info.volume_list^;
      IFEND;
    IFEND;

    status.normal := TRUE;
  PROCEND move_cycle_device_information;

?? TITLE := '  move_cycle_object_information', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to move cycle information from the local
{   sequence to the caller supplied sequence.

  PROCEDURE move_cycle_object_information
    (    local_cycle_object: fst$goi_object;
     VAR cycle_object: fst$goi_object;
     VAR p_object_information: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      archive_index: ost$positive_integers;

    cycle_object.cycle_number := local_cycle_object.cycle_number;
    cycle_object.cycle_global_file_name := local_cycle_object.cycle_global_file_name;
    cycle_object.cycle_device_class := local_cycle_object.cycle_device_class;

    IF local_cycle_object.archive_information_list = NIL THEN
      cycle_object.archive_information_list := NIL;
    ELSE
      NEXT cycle_object.archive_information_list:
            [1 .. UPPERBOUND (local_cycle_object.archive_information_list^)] IN p_object_information;
      IF cycle_object.archive_information_list = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;

      FOR archive_index := 1 TO UPPERBOUND (cycle_object.archive_information_list^) DO
        cycle_object.archive_information_list^ [archive_index].archive_entry :=
              local_cycle_object.archive_information_list^ [archive_index].archive_entry;

        IF local_cycle_object.archive_information_list^ [archive_index].amd = NIL THEN
          cycle_object.archive_information_list^ [archive_index].amd := NIL;
        ELSE
          NEXT cycle_object.archive_information_list^ [archive_index].amd:
                [[REP #SIZE (local_cycle_object.archive_information_list^ [archive_index].amd^) OF cell]]
                IN p_object_information;
          IF cycle_object.archive_information_list^ [archive_index].amd = NIL THEN
            osp$set_status_condition (pfe$info_full, status);
            RETURN;
          IFEND;

          cycle_object.archive_information_list^ [archive_index].amd^ :=
                local_cycle_object.archive_information_list^ [archive_index].amd^;
        IFEND;
      FOREND;
    IFEND;

    IF local_cycle_object.cycle_device_information = NIL THEN
      cycle_object.cycle_device_information := NIL;
    ELSE
      NEXT cycle_object.cycle_device_information IN p_object_information;
      IF cycle_object.cycle_device_information = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;

      move_cycle_device_information (cycle_object.cycle_device_class,
            local_cycle_object.cycle_device_information^, cycle_object.cycle_device_information^,
            p_object_information, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
    IFEND;

    IF local_cycle_object.cycle_information = NIL THEN
      cycle_object.cycle_information := NIL;
    ELSE
      NEXT cycle_object.cycle_information IN p_object_information;
      IF cycle_object.cycle_information = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;

      cycle_object.cycle_information^ := local_cycle_object.cycle_information^;
    IFEND;

    IF local_cycle_object.cycle_size = NIL THEN
      cycle_object.cycle_size := NIL;
    ELSE
      NEXT cycle_object.cycle_size IN p_object_information;
      IF cycle_object.cycle_size = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;

      cycle_object.cycle_size^ := local_cycle_object.cycle_size^;
    IFEND;

    cycle_object.validation_error := local_cycle_object.validation_error;

    IF local_cycle_object.file_label = NIL THEN
      cycle_object.file_label := NIL;
    ELSE
      NEXT cycle_object.file_label: [[REP #SIZE (local_cycle_object.file_label^) OF cell]]
            IN p_object_information;
      IF cycle_object.file_label = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;

      cycle_object.file_label^ := local_cycle_object.file_label^;
    IFEND;

    IF local_cycle_object.job_environment_information = NIL THEN
      cycle_object.job_environment_information := NIL;
    ELSE
      NEXT cycle_object.job_environment_information IN p_object_information;
      IF cycle_object.job_environment_information = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;

      cycle_object.job_environment_information^ := local_cycle_object.job_environment_information^;

      IF cycle_object.job_environment_information^.volume_list <> NIL THEN
        NEXT cycle_object.job_environment_information^.volume_list:
              [1 .. UPPERBOUND (local_cycle_object.job_environment_information^.volume_list^)] IN
              p_object_information;
        IF cycle_object.job_environment_information^.volume_list = NIL THEN
          osp$set_status_condition (pfe$info_full, status);
          RETURN;
        IFEND;
        cycle_object.job_environment_information^.volume_list^ := local_cycle_object.
              job_environment_information^.volume_list^;
      IFEND;

      IF cycle_object.job_environment_information^.connected_files <> NIL THEN
        NEXT cycle_object.job_environment_information^.connected_files:
              [1 .. UPPERBOUND (local_cycle_object.job_environment_information^.connected_files^)] IN
              p_object_information;
        IF cycle_object.job_environment_information^.connected_files = NIL THEN
          osp$set_status_condition (pfe$info_full, status);
          RETURN;
        IFEND;
        cycle_object.job_environment_information^.connected_files^ := local_cycle_object.
              job_environment_information^.connected_files^;
      IFEND;
    IFEND;

    status.normal := TRUE;
  PROCEND move_cycle_object_information;

?? TITLE := '  move_file_object_information', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to move file information from the local
{   sequence to the caller supplied sequence.

  PROCEDURE move_file_object_information
    (    local_file_object: fst$goi_object;
     VAR file_object: fst$goi_object;
     VAR p_object_information: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      cycle_index: ost$positive_integers;

    file_object.file_name := local_file_object.file_name;

    IF local_file_object.applicable_file_permit = NIL THEN
      file_object.applicable_file_permit := NIL;
    ELSE
      NEXT file_object.applicable_file_permit IN p_object_information;
      IF file_object.applicable_file_permit = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;

      file_object.applicable_file_permit^ := local_file_object.applicable_file_permit^;
    IFEND;

    IF local_file_object.file_information = NIL THEN
      file_object.file_information := NIL;
    ELSE
      NEXT file_object.file_information IN p_object_information;
      IF file_object.file_information = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;

      file_object.file_information^.account := local_file_object.file_information^.account;

      IF local_file_object.file_information^.logging_selection = NIL THEN
        file_object.file_information^.logging_selection := NIL;
      ELSE
        NEXT file_object.file_information^.logging_selection IN p_object_information;
        IF file_object.file_information^.logging_selection = NIL THEN
          osp$set_status_condition (pfe$info_full, status);
          RETURN;
        IFEND;

        file_object.file_information^.logging_selection^ :=
              local_file_object.file_information^.logging_selection^;
      IFEND;

      file_object.file_information^.project := local_file_object.file_information^.project;
    IFEND;

    IF local_file_object.file_log = NIL THEN
      file_object.file_log := NIL;
    ELSE
      NEXT file_object.file_log: [1 .. UPPERBOUND (local_file_object.file_log^)] IN p_object_information;
      IF file_object.file_log = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;

      file_object.file_log^ := local_file_object.file_log^;
    IFEND;

    IF local_file_object.file_permits = NIL THEN
      file_object.file_permits := NIL;
    ELSE
      NEXT file_object.file_permits: [1 .. UPPERBOUND (local_file_object.file_permits^)]
            IN p_object_information;
      IF file_object.file_permits = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;

      file_object.file_permits^ := local_file_object.file_permits^;
    IFEND;

    file_object.password := local_file_object.password;

    IF local_file_object.cycle_object_list = NIL THEN
      file_object.cycle_object_list := NIL;
    ELSE
      NEXT file_object.cycle_object_list: [1 .. UPPERBOUND (local_file_object.cycle_object_list^)]
            IN p_object_information;
      IF file_object.cycle_object_list = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;

      FOR cycle_index := 1 TO UPPERBOUND (file_object.cycle_object_list^) DO
        file_object.cycle_object_list^ [cycle_index].object_type := fsc$goi_cycle_object;
        move_cycle_object_information (local_file_object.cycle_object_list^ [cycle_index],
              file_object.cycle_object_list^ [cycle_index], p_object_information, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
      FOREND;
    IFEND;

    status.normal := TRUE;
  PROCEND move_file_object_information;

?? TITLE := '  move_object_information', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to move the information from the local
{   sequence to the caller supplied sequence.

  PROCEDURE move_object_information
    (    p_local_object_info: {i^/o^} ^fst$goi_object_information;
     VAR p_object_information: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      p_object_info: ^fst$goi_object_information;

    NEXT p_object_info IN p_object_information;
    IF p_object_info = NIL THEN
      osp$set_status_condition (pfe$info_full, status);
      RETURN;
    IFEND;

    p_object_info^.set_name := p_local_object_info^.set_name;

    IF p_local_object_info^.resolved_path = NIL THEN
      p_object_info^.resolved_path := NIL;
    ELSE
      NEXT p_object_info^.resolved_path: [#SIZE (p_local_object_info^.resolved_path^)]
            IN p_object_information;
      IF p_object_info^.resolved_path = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;

      p_object_info^.resolved_path^ := p_local_object_info^.resolved_path^;
    IFEND;

    IF p_local_object_info^.object = NIL THEN
      p_object_info^.object := NIL;
    ELSE
      NEXT p_object_info^.object IN p_object_information;
      IF p_object_info^.object = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN;
      IFEND;

      p_object_info^.object^.object_type := p_local_object_info^.object^.object_type;

      CASE p_object_info^.object^.object_type OF
      = fsc$goi_catalog_object =
        move_catalog_object_information (p_local_object_info^.object^, p_object_info^.object^,
              p_object_information, status);
      = fsc$goi_file_object =
        move_file_object_information (p_local_object_info^.object^, p_object_info^.object^,
              p_object_information, status);
      = fsc$goi_cycle_object =
        move_cycle_object_information (p_local_object_info^.object^, p_object_info^.object^,
              p_object_information, status);
      ELSE
        osp$set_status_abnormal (pfc$permanent_file_manager_id, pfe$pf_system_error,
              'Invalid object_type in move_object_information.', status);
      CASEND;
      IF NOT status.normal THEN
        RETURN;
      IFEND;
    IFEND;

    status.normal := TRUE;
  PROCEND move_object_information;

?? TITLE := '  [INLINE] reduce_subject_permit', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to reduce a subject permit and a permit
{   entry into a single subject permit by picking the one with the more
{   selective group.  In the case of equally selective groups, the child permit
{   entry will become the reduced subject permit.

  PROCEDURE [INLINE] reduce_subject_permit
    (    parental_subject_permit: pft$permit_array_entry;
         child_permit_entry: pft$permit_entry;
     VAR group_type: pft$group_types;
     VAR reduced_subject_permit: pft$permit_array_entry);

    IF child_permit_entry.entry_type = pfc$normal_permit_entry THEN
      IF child_permit_entry.group.group_type < parental_subject_permit.group.group_type THEN
        group_type := parental_subject_permit.group.group_type;
        reduced_subject_permit := parental_subject_permit;
      ELSE
        group_type := child_permit_entry.group.group_type;
        reduced_subject_permit.permit_type := parental_subject_permit.permit_type;
        reduced_subject_permit.group := child_permit_entry.group;
        reduced_subject_permit.usage_permissions := child_permit_entry.usage_permissions;
        reduced_subject_permit.share_requirements := child_permit_entry.share_requirements;
        reduced_subject_permit.application_info := child_permit_entry.application_info;
      IFEND;
    ELSE
      group_type := parental_subject_permit.group.group_type;
      reduced_subject_permit := parental_subject_permit;
    IFEND;
  PROCEND reduce_subject_permit;

?? TITLE := '  resolve_subject_permits', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to resolve the subject permit entries
{   supplied in the validation_criteria parameter of
{   pfp$get_object_information.

  PROCEDURE resolve_subject_permits
    (    path: pft$complete_path;
         authority: pft$authority;
         p_validation_criteria: {i^/o^} ^fst$goi_validation_criteria;
         p_subject_permit_id_list: {output^} ^subject_permit_id_list;
     VAR status: ost$status);

    PROCEDURE resolve_subject_permits_handler
      (    condition: pmt$condition;
           p_condition_info: ^pmt$condition_information;
           p_sfsa: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      VAR
        local_status: ost$status,
        status_id: ost$status_identifier,
        variant_path: pft$variant_path;

      variant_path.complete_path := TRUE;
      variant_path.p_complete_path := ^path;

      IF NOT process_non_local_exit THEN
        pfp$log_ascii ('***PF Condition Handler***', $pmt$ascii_logset [pmc$system_log, pmc$job_log],
              pmc$msg_origin_system, {critical_message} FALSE, local_status);
        pfp$log_path (variant_path, $pmt$ascii_logset [pmc$system_log, pmc$job_log], pmc$msg_origin_system,
              {critical_message} FALSE, local_status);
      IFEND;

      CASE condition.selector OF
      = pmc$system_conditions, pmc$block_exit_processing, mmc$segment_access_condition =
        IF process_non_local_exit THEN
          RETURN;
        IFEND;

        IF catalog_locator.attached THEN
          catalog_locator.abort_catalog_operation := TRUE;
          pfp$return_catalog (catalog_locator, local_status);
          IF NOT local_status.normal THEN
            pfp$report_system_error (local_status);
          IFEND;
        IFEND;

        osp$set_status_from_condition (status_id, condition, p_sfsa, local_status, handler_status);
        osp$recoverable_system_error ('UNEXPECTED STATUS', ^local_status);

        osp$set_status_abnormal (pfc$permanent_file_manager_id, pfe$pf_system_error,
              'PFP$R2_GET_OBJECT_INFO failure - see job log for details.', status);
        process_non_local_exit := TRUE;
        #SPOIL(process_non_local_exit);
        EXIT resolve_subject_permits;

      = pmc$user_defined_condition =
        IF condition.user_condition_name = 'OSC$JOB_RECOVERY' THEN
          process_non_local_exit := TRUE;
          #SPOIL(process_non_local_exit);
          EXIT resolve_subject_permits;
        ELSE
          pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);
        IFEND;
      ELSE
        pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);
      CASEND;

    PROCEND resolve_subject_permits_handler;

    VAR
      catalog_locator: pft$catalog_locator,
      local_path_index: pft$file_path_index,
      local_status: ost$status,
      p_internal_path: ^pft$internal_path,
      p_local_path: ^pft$complete_path,
      p_permit_list: ^pft$permit_list,
      p_physical_object: ^pft$physical_object,
      parent_charge_id: pft$charge_id,
      path_index: pft$file_path_index,
      permit_entry: pft$permit_entry,
      process_direct_permit: boolean,
      process_indirect_permit: boolean,
      process_non_local_exit: boolean,
      spil_index: ost$non_negative_integers,
      variant_path: pft$variant_path,
      vc_index: ost$non_negative_integers;

    process_non_local_exit := FALSE;
    #SPOIL(process_non_local_exit);

    process_direct_permit := FALSE;
    process_indirect_permit := FALSE;

    spil_index := 0;
    FOR vc_index := 1 TO UPPERBOUND (p_validation_criteria^) DO
      IF p_validation_criteria^ [vc_index].validation_selection = fsc$goi_subject_permit THEN
        process_direct_permit := process_direct_permit OR
              (p_validation_criteria^ [vc_index].subject_permit.permit_type = pfc$direct_permit);
        process_indirect_permit := process_indirect_permit OR
              (p_validation_criteria^ [vc_index].subject_permit.permit_type = pfc$indirect_permit);
        spil_index := spil_index + 1;
        convert_group_to_authority (p_validation_criteria^ [vc_index].subject_permit.group,
              p_subject_permit_id_list^ [spil_index].authority);
        p_subject_permit_id_list^ [spil_index].permit_type :=
              p_validation_criteria^ [vc_index].subject_permit.permit_type;
        p_validation_criteria^ [vc_index].subject_permit.group.group_type := pfc$public;
        p_validation_criteria^ [vc_index].subject_permit.usage_permissions := $pft$permit_selections [];
        p_validation_criteria^ [vc_index].subject_permit.share_requirements := - $pft$share_requirements [];
        p_validation_criteria^ [vc_index].subject_permit.application_info := osc$null_name;
      IFEND;
    FOREND;

    IF (NOT process_direct_permit) AND (NOT process_indirect_permit) THEN
      status.normal := TRUE;
      RETURN;
    IFEND;

    IF process_indirect_permit THEN

    /resolve_permit_for_each_element/
      FOR path_index := pfc$master_catalog_path_index TO UPPERBOUND (path) DO
        PUSH p_local_path: [1 .. path_index];
        FOR local_path_index := 1 TO path_index DO
          p_local_path^ [local_path_index] := path [local_path_index];
        FOREND;

        PUSH p_internal_path: [1 .. path_index];
        pfp$access_object (p_local_path^, pfc$read_access, authority, valid_objects, parent_charge_id,
              catalog_locator, p_physical_object, p_internal_path^, permit_entry, status);
        IF status.normal THEN
          osp$establish_condition_handler (^resolve_subject_permits_handler, {block_exit} TRUE);
          pfp$build_permit_list_pointer (p_physical_object^.object_entry.permit_list_locator,
                catalog_locator.p_catalog_file, p_permit_list);
          IF p_permit_list <> NIL THEN
            spil_index := 0;

            FOR vc_index := 1 TO UPPERBOUND (p_validation_criteria^) DO
              IF p_validation_criteria^ [vc_index].validation_selection = fsc$goi_subject_permit THEN
                spil_index := spil_index + 1;
                IF (p_subject_permit_id_list^ [spil_index].permit_type = pfc$indirect_permit) OR
                      (path_index = UPPERBOUND (path)) THEN
                  pfp$extract_permit_entry (p_permit_list, p_subject_permit_id_list^ [spil_index].authority,
                        permit_entry);
                  reduce_subject_permit (p_validation_criteria^ [vc_index].subject_permit, permit_entry,
                        p_subject_permit_id_list^ [spil_index].group_type,
                        p_validation_criteria^ [vc_index].subject_permit);
                IFEND;
              IFEND;
            FOREND;
          IFEND;

          osp$disestablish_cond_handler;
          pfp$return_catalog (catalog_locator, local_status);
          pfp$process_unexpected_status (local_status);
        IFEND;

        IF NOT status.normal THEN
          EXIT /resolve_permit_for_each_element/;
        IFEND;
      FOREND /resolve_permit_for_each_element/;

    ELSE
      PUSH p_internal_path: [1 .. UPPERBOUND (path)];
      pfp$access_object (path, pfc$read_access, authority, valid_objects, parent_charge_id, catalog_locator,
            p_physical_object, p_internal_path^, permit_entry, status);
      IF status.normal THEN
        osp$establish_condition_handler (^resolve_subject_permits_handler, {block_exit} TRUE);
        pfp$build_permit_list_pointer (p_physical_object^.object_entry.permit_list_locator,
              catalog_locator.p_catalog_file, p_permit_list);
        IF p_permit_list <> NIL THEN
          spil_index := 0;

          FOR vc_index := 1 TO UPPERBOUND (p_validation_criteria^) DO
            IF p_validation_criteria^ [vc_index].validation_selection = fsc$goi_subject_permit THEN
              spil_index := spil_index + 1;
              pfp$extract_permit_entry (p_permit_list, p_subject_permit_id_list^ [spil_index].authority,
                    permit_entry);
              reduce_subject_permit (p_validation_criteria^ [vc_index].subject_permit, permit_entry,
                    p_subject_permit_id_list^ [spil_index].group_type,
                    p_validation_criteria^ [vc_index].subject_permit);
            IFEND;
          FOREND;
        IFEND;

        osp$disestablish_cond_handler;
        pfp$return_catalog (catalog_locator, local_status);
        pfp$process_unexpected_status (local_status);
      IFEND;
    IFEND;

    { If any of the subjects is not permitted access to the object, then return
    { an abnormal status.

    IF status.normal THEN
      FOR vc_index := 1 TO UPPERBOUND (p_validation_criteria^) DO
        IF (p_validation_criteria^ [vc_index].validation_selection = fsc$goi_subject_permit) AND
              (p_validation_criteria^ [vc_index].subject_permit.usage_permissions = $pft$permit_selections [])
              THEN
          variant_path.complete_path := TRUE;
          variant_path.p_complete_path := ^path;
          pfp$set_status_abnormal (variant_path, pfe$unknown_item, status);
          RETURN;
        IFEND;
      FOREND;
    IFEND;
  PROCEND resolve_subject_permits;

?? TITLE := '  store_resolved_path', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to convert an evaluated file reference,
{   which has already been resolved, to a string and to store the string in an
{   object information sequence.

  PROCEDURE store_resolved_path
    (    evaluated_file_reference: fst$evaluated_file_reference;
         p_object_info: {output^} ^fst$goi_object_information;
     VAR p_object_information: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      fs_path: fst$path,
      fs_path_size: fst$path_size;

    clp$convert_file_ref_to_string (evaluated_file_reference, {include_open_position} TRUE, fs_path,
          fs_path_size, status);

    IF status.normal THEN
      NEXT p_object_info^.resolved_path: [fs_path_size] IN p_object_information;
      IF p_object_info^.resolved_path = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
      ELSE
        p_object_info^.resolved_path^ := fs_path (1, fs_path_size);
      IFEND;
    IFEND;
  PROCEND store_resolved_path;

?? TITLE := '  update_fmd', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to update a cycle's file media descriptor
{   if necessary.
{
{ NOTE:
{   The dm_file_information is only valid if dm_file_information_valid is TRUE.

  PROCEDURE update_fmd
    (    p_path: ^pft$complete_path;
         family_location: pft$family_location;
         p_physical_cycle: {i^/o^} ^pft$physical_cycle;
         p_catalog_file: {i^/o^} ^pft$catalog_file;
         device_class: rmt$device_class;
     VAR p_physical_fmd: ^pft$physical_fmd;
     VAR attached_for_write: boolean;
     VAR dm_file_information_valid: boolean;
     VAR dm_file_information: dmt$file_information;
     VAR status: ost$status);

    VAR
      existing_sft_entry: dmt$existing_sft_entry,
      file_damaged: boolean,
      file_modified: boolean,
      fmd_modified: boolean,
      local_status: ost$status,
      shared_queue: mmt$shared_queue,
      system_file_id: gft$system_file_identifier;

    pfp$build_fmd_pointer (p_physical_cycle^.cycle_entry.fmd_locator, p_catalog_file, p_physical_fmd);

    status.normal := TRUE;
    attached_for_write := FALSE;
    dm_file_information_valid := FALSE;

    IF (device_class = rmc$magnetic_tape_device) OR (p_physical_fmd = NIL) THEN
      RETURN;
    ELSE
      attached_for_write := pfp$cycle_attached_for_write (p_physical_cycle);
      shared_queue := pfp$shared_queue (p_physical_cycle^.cycle_entry.shared_queue_info,
            -$pft$share_selections []);
      IF attached_for_write OR (p_physical_cycle^.cycle_entry.shared_queue_info.defined AND
           (p_physical_cycle^.cycle_entry.attach_status.attach_count > 1)) THEN
        dmp$attach_file (p_physical_cycle^.cycle_entry.internal_cycle_name, gfc$fk_job_permanent_file,
              p_physical_fmd^.fmd, $pft$usage_selections [], -$pft$share_selections [],
              pfc$average_share_history, pfc$maximum_pf_length, {restricted_attach} FALSE,
              {exit_on_unknown_file} TRUE, (family_location = pfc$server_mainframe),
              shared_queue, file_damaged, system_file_id, existing_sft_entry, status);
        IF NOT status.normal THEN
          status.normal := TRUE;
          RETURN;
        IFEND;

        IF existing_sft_entry = dmc$normal_entry THEN
          pfp$detach_permanent_file (p_path, system_file_id, $pft$usage_selections [],
                {catalog_access_allowed} TRUE, p_physical_cycle, p_catalog_file, dmc$df_ignore_trimmed_length,
                fmd_modified, dm_file_information, local_status);
          pfp$process_unexpected_status (local_status);
          dm_file_information_valid := local_status.normal;

          IF fmd_modified THEN
            pfp$build_fmd_pointer (p_physical_cycle^.cycle_entry.fmd_locator, p_catalog_file, p_physical_fmd);
          IFEND;
        ELSE
          attached_for_write := FALSE;
          pfp$reconcile_fmd (p_path, p_physical_cycle^.cycle_entry.internal_cycle_name, existing_sft_entry,
                {update_catalog} TRUE, p_catalog_file, p_physical_cycle, p_physical_fmd, status);
          IF NOT status.normal THEN
            status.normal := TRUE;
            RETURN;
          IFEND;

          {
          { Attach and detach the file to get the dm_file_information and update the eoi in the catalog.
          {

          dmp$attach_file (p_physical_cycle^.cycle_entry.internal_cycle_name, gfc$fk_job_permanent_file,
                p_physical_fmd^.fmd, $pft$usage_selections [], -$pft$share_selections [],
                pfc$average_share_history, pfc$maximum_pf_length, {restricted_attach} FALSE,
                {exit_on_unknown_file} FALSE, (family_location = pfc$server_mainframe),
                pfp$shared_queue (p_physical_cycle^.cycle_entry.shared_queue_info, -$pft$share_selections []),
                file_damaged, system_file_id, existing_sft_entry, status);
          IF NOT status.normal THEN
            status.normal := TRUE;
            RETURN;
          IFEND;

          pfp$detach_permanent_file (p_path, system_file_id, $pft$usage_selections [],
                {catalog_access_allowed} TRUE, p_physical_cycle, p_catalog_file, dmc$df_ignore_trimmed_length,
                fmd_modified, dm_file_information, local_status);
          pfp$process_unexpected_status (local_status);
          dm_file_information_valid := local_status.normal;

          p_physical_cycle^.cycle_entry.device_information.eoi := dm_file_information.eoi_byte_address;
          p_physical_cycle^.cycle_entry.device_information.bytes_allocated :=
                dm_file_information.total_allocated_length;

          p_physical_cycle^.cycle_entry.attach_status := pfv$unattached_status;
          pfp$compute_checksum (#LOC (p_physical_cycle^.cycle_entry), #SIZE (pft$cycle_entry),
                p_physical_cycle^.checksum);
        IFEND;
      IFEND;
    IFEND;
  PROCEND update_fmd;

?? TITLE := '  update_stale_cycle_entry', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to update new items which were added to
{   the cycle entry in R1.4.1.  These items will be stale if the cycle was
{   created or modified by an R1.3.1 or older version of the system.
{
{ NOTE:
{   This procedure should be deleted two releases after R1.4.1 when it is no
{   longer necessary to support an upgrade from an R1.3.1 or earlier system.

  PROCEDURE update_stale_cycle_entry
    (    family_location: pft$family_location;
         p_path: ^pft$complete_path;
         stored_fmd: dmt$stored_fmd;
         p_physical_cycle: {i^/o^} ^pft$physical_cycle;
         p_catalog_file: {i^/o^} ^pft$catalog_file);

    VAR
      dm_file_information: dmt$file_information,
      existing_sft_entry: dmt$existing_sft_entry,
      file_damaged: boolean,
      file_modified: boolean,
      fmd_modified: boolean,
      local_status: ost$status,
      system_file_id: gft$system_file_identifier;

    dmp$attach_file (p_physical_cycle^.cycle_entry.internal_cycle_name, gfc$fk_job_permanent_file, stored_fmd,
          $pft$usage_selections [], -$pft$share_selections [], pfc$average_share_history,
          pfc$maximum_pf_length, {restricted_attach} FALSE, {exit_on_unknown_file} TRUE,
          (family_location = pfc$server_mainframe),
          pfp$shared_queue (p_physical_cycle^.cycle_entry.shared_queue_info, -$pft$share_selections []),
          file_damaged, system_file_id, existing_sft_entry, local_status);
    IF NOT local_status.normal THEN
      RETURN;
    IFEND;

    IF existing_sft_entry = dmc$normal_entry THEN
      pfp$update_stale_cycle_entry (system_file_id, p_physical_cycle, local_status);

      pfp$detach_permanent_file (p_path, system_file_id, $pft$usage_selections [],
            {catalog_access_allowed} TRUE, p_physical_cycle, p_catalog_file, dmc$df_ignore_file_info,
            fmd_modified, dm_file_information, local_status);
      pfp$process_unexpected_status (local_status);
    IFEND;
  PROCEND update_stale_cycle_entry;

?? TITLE := '  [INLINE] validate_subject_permits', EJECT ??

  PROCEDURE [INLINE] validate_subject_permits
    (    p_permit_list: {input} ^pft$permit_list;
         p_old_subject_permit_id_list: {input^} ^subject_permit_id_list;
         p_new_subject_permit_id_list: {output^} ^subject_permit_id_list;
     VAR all_subjects_are_permitted: boolean);

    VAR
      permit_entry: pft$permit_entry,
      subject_permit_index: ost$positive_integers;

    FOR subject_permit_index := 1 TO UPPERBOUND (p_old_subject_permit_id_list^) DO
      pfp$extract_permit_entry (p_permit_list, p_old_subject_permit_id_list^ [subject_permit_index].authority,
            permit_entry);
      IF (permit_entry.entry_type = pfc$free_permit_entry) OR (permit_entry.group.group_type <
            p_old_subject_permit_id_list^ [subject_permit_index].group_type) THEN
        p_new_subject_permit_id_list^ [subject_permit_index] :=
              p_old_subject_permit_id_list^ [subject_permit_index];
      ELSEIF permit_entry.usage_permissions <> $pft$permit_selections [] THEN
        p_new_subject_permit_id_list^ [subject_permit_index] :=
              p_old_subject_permit_id_list^ [subject_permit_index];
        p_new_subject_permit_id_list^ [subject_permit_index].group_type := permit_entry.group.group_type;
      ELSE
        all_subjects_are_permitted := FALSE;
        RETURN;
      IFEND;
    FOREND;

    all_subjects_are_permitted := TRUE;
  PROCEND validate_subject_permits;
?? TITLE := '  volume_list_condition', EJECT ??

  FUNCTION [INLINE] volume_list_condition
    (    catalog_object: boolean;
         volume_condition_list: fst$volume_condition_list): fst$file_access_condition;

    VAR
      i: ost$non_negative_integers,
      conditions: fst$file_access_conditions;

    conditions := $fst$file_access_conditions [];

    FOR i := LOWERBOUND (volume_condition_list) TO UPPERBOUND (volume_condition_list) DO
      conditions := conditions + $fst$file_access_conditions [volume_condition_list [i]];
    FOREND;

    IF fsc$media_missing IN conditions THEN
      IF catalog_object THEN
        volume_list_condition := fsc$catalog_media_missing;
      ELSE
        volume_list_condition := fsc$media_missing;
      IFEND;
    ELSEIF fsc$volume_unavailable IN conditions THEN
      IF catalog_object THEN
        volume_list_condition := fsc$catalog_volume_unavailable;
      ELSE
        volume_list_condition := fsc$volume_unavailable;
      IFEND;
    ELSEIF fsc$space_unavailable IN conditions THEN
      volume_list_condition := fsc$space_unavailable;
    ELSE
      volume_list_condition := fsc$null_file_access_condition;
    IFEND;
  FUNCEND volume_list_condition;

?? OLDTITLE, SKIP := 2 ??
MODEND pfm$r2_get_object_information;
