?? RIGHT := 110 ??
?? TITLE := 'NOS/VE Backup/Restore Utilities : Backup File Input' ??
MODULE pum$backup_file_input;

{ PURPOSE:
{   This module contains those routines that read from the backup file.  These
{   routines are used by the restore permanent file utility.

?? NEWTITLE := '  Global Declarations Referenced by this module' ??
?? PUSH (LISTEXT := ON) ??
*copyc fst$path
*copyc osd$integer_limits
*copyc ost$date_time
*copyc ost$name
*copyc pfc$null_shared_queue
*copyc pft$archive_identification
*copyc pfe$external_archive_conditions
*copyc pfe$internal_error_conditions
*copyc pft$cycle_info_desc_version_1
*copyc pft$cycle_info_desc_version_2
*copyc pft$date_time
*copyc pmt$comparison_result
*copyc pud$backup_file
*copyc pud$hierarchy_list
*copyc pud$list_options
*copyc pue$error_condition_codes
*copyc put$selected_object
?? POP ??
?? EJECT ??
*copyc amp$close
*copyc avp$family_administrator
*copyc avp$system_administrator
*copyc clp$get_fs_path_string
*copyc fsp$build_file_ref_from_elems
*copyc fsp$change_cycle_date_time
*copyc osp$append_status_integer
*copyc osp$append_status_parameter
*copyc osp$enforce_exception_policies
*copyc osp$file_access_condition
*copyc osp$set_status_abnormal
*copyc osv$initial_exception_context
*copyc pfp$convert_device_class_to_rm
*copyc pfp$convert_pft$path_to_fs_path
*copyc pfp$delete_all_archive_entries
*copyc pfp$delete_cycle_data
*copyc pfp$find_archive_info
*copyc pfp$find_cycle_array
*copyc pfp$find_cycle_array_extended
*copyc pfp$find_cycle_array_version_2
*copyc pfp$find_cycle_directory
*copyc pfp$find_cycle_media
*copyc pfp$find_file_description
*copyc pfp$find_next_archive_entry
*copyc pfp$get_object_information
*copyc pfp$get_ownership
*copyc pfp$put_archive_info
*copyc pfp$put_cycle_info
*copyc pfp$put_family_info
*copyc pfp$put_item_info
*copyc pfp$put_master_catalog_info
*copyc pmp$date_time_compare
*copyc pup$build_entry
*copyc pup$build_new_online_cat_head
*copyc pup$check_cycle_access
*copyc pup$compare_item_descriptor
*copyc pup$compare_paths
*copyc pup$determine_if_item_exists
*copyc pup$display_boolean
*copyc pup$display_item_descriptor
*copyc pup$display_line
*copyc pup$display_blank_lines
*copyc pup$find_cycle_info_record
*copyc pup$format_date_time
*copyc pup$get_file_password
*copyc pup$get_item_descriptor
*copyc pup$get_next_hierarchy_list
*copyc pup$get_next_record_header
*copyc pup$get_part
*copyc pup$physical_path_length
*copyc pup$restore_cycle_item
*copyc pup$set_abnormal_entry_status
*copyc pup$set_object_abnormal
*copyc pup$skip_logical_partition
*copyc pup$skip_physical_partition
*copyc pup$validate_n_n_minus_1
*copyc pup$verify_catalog_path
*copyc pup$verify_file_path
*copyc pup$write_os_status
*copyc pup$write_path
*copyc pup$write_status_to_listing
*copyc pup$write_sub_path
*copyc puv$backup_criteria
*copyc puv$create_objects
*copyc puv$cycle_display_selections
*copyc puv$mass_storage_info
*copyc puv$null_original_unique_name
*copyc puv$null_res_cycle_array_ent_sp
*copyc puv$p_included_volumes
*copyc puv$purge_cycle_options
*copyc puv$replace_cycle_data
*copyc puv$require_modification_match
*copyc puv$respf_backup_file_version
*copyc puv$respf_backup_file_version
*copyc puv$restore_archive_information
*copyc puv$trace_selected
*copyc puv$volumes_switched_forward

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

    CONST
      include_radix = TRUE,
      radix = 10;

    VAR
      p_cycle_array_extended_record: pft$p_info_record := NIL,
      p_cycle_directory_array: pft$p_cycle_directory_array := NIL;

?? TITLE := '    [XDCL] pup$find_restore_entry ', EJECT ??
*copyc puh$find_restore_entry

  PROCEDURE [XDCL] pup$find_restore_entry (entry: put$entry;
        catalog_header: put$catalog_header;
    VAR backup_file_id: put$file_identifier;
    VAR file_position: put$file_position;
    VAR status: ost$status);

    VAR
      entry_found: boolean,
      local_status: ost$status,
      p_item_description: ^put$backup_item_descriptor,
      record_header: put$backup_file_record_header,
      requested_subset_found: boolean,
      stored_backup_file_version: put$backup_file_version_name;

    entry_found := FALSE;

  /loop_through_partitions/
    REPEAT
      pup$locate_valid_version (backup_file_id, stored_backup_file_version, file_position, status);
      IF status.normal AND (file_position <> puc$eoi) THEN
        pup$get_next_record_header (backup_file_id, record_header, file_position, status);
        IF status.normal THEN
          IF (record_header.kind = puc$backup_item_identifier) AND (record_header.size > 0) THEN
            ALLOCATE p_item_description: [1 .. record_header.size];
            pup$get_item_descriptor (backup_file_id, p_item_description^, file_position, status);
            IF status.normal THEN
              pup$compare_item_descriptor (entry, catalog_header, p_item_description^.pf_utility_entry,
                    p_item_description^.catalog_header, entry_found, requested_subset_found);
            IFEND;
            FREE p_item_description;
          ELSE
            osp$set_status_abnormal (puc$pf_utility_id, pue$unexpected_item_requested, ' identifier', status);
          IFEND;
        IFEND;
        pup$write_os_status (status, local_status);
        status.normal := TRUE;
        IF NOT entry_found AND (file_position = puc$mid_partition) THEN
          pup$skip_logical_partition (backup_file_id, file_position, status);
        IFEND;
      IFEND;
    UNTIL entry_found OR (file_position = puc$eoi) OR (NOT status.normal);

    IF status.normal AND NOT entry_found THEN
      pup$set_abnormal_entry_status (entry, pue$no_restore_no_find, status);
    IFEND;
  PROCEND pup$find_restore_entry;

?? TITLE := '    [XDCL] pup$get_backup_cycle_info ', EJECT ??

  PROCEDURE [XDCL] pup$get_backup_cycle_info
   (VAR backup_file_id: put$file_identifier;
    VAR file_position: put$file_position;
    VAR cycle_array_entry: pft$cycle_array_entry_version_2;
    VAR p_file_media_descriptor: ^SEQ ( * );
    VAR status: ost$status);

{  This routine extracts the cycle array entry from the backup file.

    VAR
      fmd_size: integer,
      p_cycle_info_desc_version_1: ^pft$cycle_info_desc_version_1,
      p_cycle_info_desc_version_2: ^pft$cycle_info_desc_version_2,
      p_cycle_info_fmd: ^SEQ ( * ),
      p_fmd: ^SEQ ( * ),
      record_header: put$backup_file_record_header,
      rm_device_class: rmt$device_class,
      transfer_count: amt$file_length;

    pup$get_next_record_header (backup_file_id, record_header, file_position, status);
    IF status.normal THEN
      IF (file_position = puc$mid_partition) AND (record_header.kind = puc$backup_cycle_info) THEN
        IF puv$respf_backup_file_version = puc$backup_file_version_1 THEN
          PUSH p_cycle_info_desc_version_1;
          pup$get_part (backup_file_id, p_cycle_info_desc_version_1, #SIZE (p_cycle_info_desc_version_1^),
                file_position, transfer_count, status);
          IF status.normal THEN
            cycle_array_entry.bytes_allocated := 0;
            cycle_array_entry.cycle_damage_symptoms := $fst$cycle_damage_symptoms [];
            cycle_array_entry.cycle_number := p_cycle_info_desc_version_1^.cycle_number;
            cycle_array_entry.cycle_statistics := p_cycle_info_desc_version_1^.cycle_statistics;
            cycle_array_entry.data_modification_date_time :=
                  p_cycle_info_desc_version_1^.cycle_statistics.modification_date_time;
            cycle_array_entry.data_residence := pfc$unreleasable_data;
            cycle_array_entry.device_class := rmc$mass_storage_device;
            cycle_array_entry.eoi := 0;
            cycle_array_entry.expiration_date_time := p_cycle_info_desc_version_1^.expiration_date_time;
            cycle_array_entry.original_unique_name := puv$null_original_unique_name;
            cycle_array_entry.retrieve_option := pfc$always_retrieve;
            cycle_array_entry.shared_queue_info.defined := FALSE;
            cycle_array_entry.site_archive_option := pfc$null_site_archive_option;
            cycle_array_entry.site_backup_option := pfc$null_site_backup_option;
            cycle_array_entry.site_release_option := pfc$null_site_release_option;
            cycle_array_entry.sparse_allocation := FALSE;
            cycle_array_entry.reserved_cycle_array_entry_sp := puv$null_res_cycle_array_ent_sp;
            p_file_media_descriptor := NIL;
          IFEND;
        ELSEIF puv$respf_backup_file_version = puc$backup_file_version_2 THEN
          IF record_header.size > (#SIZE(pft$cycle_info_desc_version_2: [[REP 1 OF cell]]) - 1) THEN
            fmd_size := record_header.size - (#SIZE(pft$cycle_info_desc_version_2: [[REP 1 OF cell]]) - 1);
          ELSE
            fmd_size := 1;
          IFEND;
          PUSH p_cycle_info_desc_version_2: [[REP fmd_size OF cell]];
          pup$get_part (backup_file_id, p_cycle_info_desc_version_2, record_header.size, file_position,
                transfer_count, status);
          IF status.normal AND p_cycle_info_desc_version_2^.sparse_backup_file_format THEN
            osp$set_status_abnormal (puc$pf_utility_id, pfe$sparse_allocation_format,
                 'backup cycle info', status);
          IFEND;
          IF status.normal AND ((p_cycle_info_desc_version_2^.device_class <> pfc$magnetic_tape_device) AND
                (p_cycle_info_desc_version_2^.device_class <> pfc$mass_storage_device)) THEN
            osp$set_status_abnormal (puc$pf_utility_id, pfe$unsupported_device_class,
                 'backup cycle info', status);
          IFEND;
          IF status.normal THEN
            cycle_array_entry.bytes_allocated := 0;
            cycle_array_entry.cycle_damage_symptoms := p_cycle_info_desc_version_2^.cycle_damage_symptoms;
            cycle_array_entry.cycle_number := p_cycle_info_desc_version_2^.cycle_number;
            cycle_array_entry.cycle_statistics := p_cycle_info_desc_version_2^.cycle_statistics;
            cycle_array_entry.data_modification_date_time :=
                  p_cycle_info_desc_version_2^.data_modification_date_time;
            cycle_array_entry.data_residence := pfc$unreleasable_data;
            pfp$convert_device_class_to_rm (p_cycle_info_desc_version_2^.device_class, rm_device_class);
            cycle_array_entry.device_class := rm_device_class;
            cycle_array_entry.eoi := 0;
            cycle_array_entry.expiration_date_time := p_cycle_info_desc_version_2^.expiration_date_time;
            cycle_array_entry.original_unique_name := p_cycle_info_desc_version_2^.original_unique_name;
            cycle_array_entry.retrieve_option := p_cycle_info_desc_version_2^.retrieve_option;
            cycle_array_entry.shared_queue_info := p_cycle_info_desc_version_2^.shared_queue_info;
            cycle_array_entry.site_archive_option := p_cycle_info_desc_version_2^.site_archive_option;
            cycle_array_entry.site_backup_option := p_cycle_info_desc_version_2^.site_backup_option;
            cycle_array_entry.site_release_option := p_cycle_info_desc_version_2^.site_release_option;
            cycle_array_entry.sparse_allocation := FALSE;
            cycle_array_entry.reserved_cycle_array_entry_sp := puv$null_res_cycle_array_ent_sp;
            IF fmd_size > 1 THEN
              ALLOCATE p_file_media_descriptor: [[REP fmd_size OF cell]];
              p_fmd := ^p_cycle_info_desc_version_2^.file_media_descriptor;
              NEXT p_cycle_info_fmd: [[REP fmd_size OF cell]] IN p_fmd;
              p_file_media_descriptor^ := p_cycle_info_fmd^;
            ELSE
              p_file_media_descriptor := NIL;
            IFEND;
          IFEND;
        IFEND;
      ELSE
        osp$set_status_abnormal (puc$pf_utility_id, pue$unusable_restore_file, 'backup cycle info', status);
      IFEND;
    IFEND;
  PROCEND pup$get_backup_cycle_info;

?? TITLE := '    [XDCL] pup$locate_valid_version ', EJECT ??

  PROCEDURE [XDCL] pup$locate_valid_version (
    VAR backup_file_id: put$file_identifier;
    VAR stored_backup_file_version_name: put$backup_file_version_name;
    VAR file_position: put$file_position;
    VAR status: ost$status);

    VAR
      local_status: ost$status,
      transfer_count: amt$file_length;

  /search_for_valid_version/
    WHILE TRUE DO
      pup$get_part (backup_file_id, ^stored_backup_file_version_name, #SIZE (stored_backup_file_version_name),
            file_position, transfer_count, status);
      IF status.normal THEN
        validate_version_number (stored_backup_file_version_name, backup_file_id, status);
      IFEND;
      IF status.normal OR ((NOT status.normal) AND( status.condition = pue$incompatible_backup_version)) THEN
        EXIT /search_for_valid_version/;
      ELSEIF file_position = puc$eoi THEN
        status.normal := TRUE;
        EXIT /search_for_valid_version/;
      ELSE
        IF puv$volumes_switched_forward THEN
          display (' eat status');
          display_status (status);
        ELSE
          pup$write_os_status (status, local_status);
        IFEND;
        pup$skip_logical_partition (backup_file_id, file_position, status);
        IF (NOT status.normal) OR (file_position = puc$eoi) THEN
          EXIT /search_for_valid_version/;
        IFEND;
      IFEND;
    WHILEND /search_for_valid_version/;

  PROCEND pup$locate_valid_version;

?? TITLE := '  [XDCL] pup$restore_catalog_info', EJECT ??

  PROCEDURE [XDCL] pup$restore_catalog_info
    (    new_online_cat_header: put$catalog_header;
     VAR backup_file_id: put$file_identifier;
     VAR file_position: put$file_position;
     VAR status: ost$status);

    VAR
      all_permits_restored: boolean,
      backup_file_version: pft$backup_file_version,
      context: ost$ecp_exception_context,
      initial_pass: boolean,
      local_status: ost$status,
      p_info_record: pft$p_info_record,
      permit_status: ost$status,
      record_header: put$backup_file_record_header,
      transfer_count: amt$file_length;

    initial_pass := TRUE;
    pup$write_path (new_online_cat_header.path, local_status);

    { Get item info.

    pup$get_next_record_header (backup_file_id, record_header, file_position, status);
    IF status.normal THEN
      IF (file_position = puc$mid_partition) AND ((record_header.kind = puc$backup_family_info) OR
            (record_header.kind = puc$backup_catalog_info)) AND (record_header.size > 0) THEN
        PUSH p_info_record: [[REP record_header.size OF cell]];
        pup$get_part (backup_file_id, p_info_record, #SIZE (p_info_record^), file_position,
              transfer_count, status);
      ELSE
        osp$set_status_abnormal (puc$pf_utility_id, pue$unusable_restore_file, ' info ', status);
      IFEND;
    IFEND;

    { Put item info.

    IF status.normal THEN
      CASE new_online_cat_header.logical_path_length OF
      = pfc$family_name_index =
        REPEAT
          pfp$put_family_info (new_online_cat_header.set_name,
                new_online_cat_header.path [pfc$family_name_index], p_info_record, status);
          IF NOT status.normal THEN
            IF initial_pass THEN
              initial_pass := FALSE;
              context := osv$initial_exception_context;
              context.file.selector := osc$ecp_pf_path;
              context.file.file_reference := ^new_online_cat_header.path [pfc$family_name_index];
              context.catalog_object := TRUE;
            IFEND;
            context.condition_status := status;
            osp$enforce_exception_policies (context);
            status := context.condition_status;
          IFEND;
        UNTIL status.normal OR (NOT osp$file_access_condition (status)) OR (NOT context.wait);
      = pfc$master_catalog_name_index =
        REPEAT
          pfp$put_master_catalog_info (new_online_cat_header.set_name,
                new_online_cat_header.path [pfc$family_name_index],
                new_online_cat_header.path [pfc$master_catalog_name_index], p_info_record, status);
          IF NOT status.normal THEN
            IF initial_pass THEN
              initial_pass := FALSE;
              context := osv$initial_exception_context;
              context.file.selector := osc$ecp_pf_path;
              context.file.file_reference := ^new_online_cat_header.path [pfc$master_catalog_name_index];
              context.catalog_object := TRUE;
            IFEND;
            context.condition_status := status;
            osp$enforce_exception_policies (context);
            status := context.condition_status;
          IFEND;
        UNTIL status.normal OR (NOT osp$file_access_condition (status)) OR (NOT context.wait);
      ELSE
        IF puv$respf_backup_file_version = puc$backup_file_version_1 THEN
          backup_file_version := pfc$backup_file_version_1;
        ELSEIF puv$respf_backup_file_version = puc$backup_file_version_2 THEN
          backup_file_version := pfc$backup_file_version_2;
        IFEND;
        pfp$put_item_info (new_online_cat_header.path, p_info_record, {puv$restore_archive_information}
              FALSE, puv$backup_criteria, backup_file_version, all_permits_restored, status);
      CASEND;
    IFEND;

    IF status.normal THEN
      IF NOT all_permits_restored THEN
        osp$set_status_abnormal (puc$pf_utility_id, pue$not_all_permits_restored, 'catalog', status);
        pup$write_os_status (status, local_status);
      IFEND;
    ELSE
      IF NOT all_permits_restored THEN
        osp$set_status_abnormal (puc$pf_utility_id, pue$not_all_permits_restored, 'catalog', permit_status);
        pup$write_os_status (permit_status, local_status);
      IFEND;

      IF status.condition = pfe$name_already_subcatalog THEN
        pup$display_line ('    -- CATALOG ALREADY EXISTS', local_status);
      ELSE
        pup$write_os_status (status, local_status);
      IFEND;
    IFEND;
  PROCEND pup$restore_catalog_info;

?? TITLE := '    [XDCL] pup$restore_selected_objects ', EJECT ??

  PROCEDURE [XDCL] pup$restore_selected_objects
    (    p_selected_objects: ^put$selected_object;
     VAR backup_file_id: put$file_identifier;
     VAR status: ost$status);

    VAR
      all_objects_restored: boolean,
      cycle_count: integer,
      cycle_index: integer,
      entry_found: boolean,
      file_position: put$file_position,
      found_entry: put$entry,
      local_entry_found: boolean,
      local_requested_subset_found: boolean,
      local_status: ost$status,
      new_entry: put$entry,
      p_current_object: ^put$selected_object,
      p_cycle_entries: ^array [1 .. *] of put$entry,
      p_cycle_object: ^put$selected_object,
      p_item_description: ^put$backup_item_descriptor,
      p_search_object: ^put$selected_object,
      p_selected_cycles: ^array [1 .. *] of put$selected_cycle_info,
      p_subset_object: ^put$selected_object,
      record_header: put$backup_file_record_header,
      requested_subset_found: boolean,
      restore_entry: boolean,
      stored_backup_file_version: put$backup_file_version_name;

    entry_found := FALSE;

  /loop_through_partitions/
    REPEAT
      pup$locate_valid_version (backup_file_id, stored_backup_file_version, file_position, status);
      IF status.normal AND (file_position <> puc$eoi) THEN
        pup$get_next_record_header (backup_file_id, record_header, file_position, status);
        IF status.normal THEN
          IF (record_header.kind = puc$backup_item_identifier) AND (record_header.size >= 1) THEN
            ALLOCATE p_item_description: [1 .. record_header.size];
            pup$get_item_descriptor (backup_file_id, p_item_description^, file_position, status);
            IF status.normal THEN
              all_objects_restored := TRUE;
              cycle_count := 0;
              entry_found := FALSE;
              found_entry := p_item_description^.pf_utility_entry;
              p_cycle_entries := NIL;
              p_search_object := p_selected_objects;
              p_selected_cycles := NIL;
              p_subset_object := NIL;
              requested_subset_found := FALSE;
              restore_entry := FALSE;

            /search_selected_objects/
              WHILE p_search_object <> NIL DO
                all_objects_restored := (all_objects_restored AND p_search_object^.object_restored);
                pup$compare_item_descriptor (p_search_object^.entry, p_search_object^.p_catalog_header^,
                      p_item_description^.pf_utility_entry, p_item_description^.catalog_header,
                      local_entry_found, local_requested_subset_found);
                IF local_entry_found THEN
                  IF NOT entry_found THEN
                    entry_found := TRUE;
                    p_current_object := p_search_object;
                  IFEND;
                  IF (p_search_object^.entry.entry_type = puc$valid_pf_entry) AND
                        (p_search_object^.selected_cycle_info.selected_cycle.cycle_specified OR
                        p_search_object^.selected_cycle_info.new_selected_cycle.cycle_specified) THEN
                    cycle_count := cycle_count + 1;
                  IFEND;
                ELSEIF local_requested_subset_found THEN
                  IF NOT requested_subset_found THEN
                    p_subset_object := p_search_object;
                    requested_subset_found := TRUE;
                  IFEND;
                  IF (p_search_object^.entry.entry_type = puc$valid_pf_entry) AND
                        (p_search_object^.selected_cycle_info.selected_cycle.cycle_specified OR
                        p_search_object^.selected_cycle_info.new_selected_cycle.cycle_specified) THEN
                    cycle_count := cycle_count + 1;
                  IFEND;
                IFEND;
                p_search_object := p_search_object^.link;
              WHILEND /search_selected_objects/;

              IF requested_subset_found AND (NOT entry_found) THEN
                p_current_object := p_subset_object;
              IFEND;

              IF entry_found OR requested_subset_found THEN
                IF p_item_description^.pf_utility_entry.entry_type = puc$valid_pf_entry THEN
                  restore_entry := TRUE;
                  new_entry := p_current_object^.new_entry;
                  IF cycle_count > 0 THEN
                    PUSH p_selected_cycles: [1 .. cycle_count];
                    PUSH p_cycle_entries: [1 .. cycle_count];
                    p_search_object := p_selected_objects;
                    cycle_index := 1;
                  /collect_selected_cycles/
                    WHILE p_search_object <> NIL DO
                      pup$compare_item_descriptor (p_search_object^.entry, p_search_object^.p_catalog_header^,
                            p_item_description^.pf_utility_entry, p_item_description^.catalog_header,
                            local_entry_found, local_requested_subset_found);
                      IF (local_entry_found OR local_requested_subset_found) AND
                            (p_search_object^.entry.entry_type = puc$valid_pf_entry) THEN
                        p_search_object^.object_restored := TRUE;
                        p_selected_cycles^ [cycle_index] := p_search_object^.selected_cycle_info;
                        p_cycle_entries^ [cycle_index].entry_type := puc$valid_cycle_entry;
                        p_cycle_entries^ [cycle_index].pf_selector.pfn :=
                              p_search_object^.entry.pfn;
                        p_cycle_entries^ [cycle_index].pf_selector.cycle_selector :=
                              p_search_object^.selected_cycle_info.selected_cycle.cycle_selector;
                        cycle_index := cycle_index + 1;
                      IFEND;
                      p_search_object := p_search_object^.link;
                    WHILEND /search_selected_objects/;
                  IFEND;
                  pup$write_sub_path (p_current_object^.p_new_catalog_header^.path,
                        LOWERBOUND (p_current_object^.p_new_catalog_header^.path),
                        UPPERBOUND (p_current_object^.p_new_catalog_header^.path) - 1, status);
                ELSEIF p_item_description^.pf_utility_entry.entry_type = puc$valid_cycle_entry THEN
                  p_search_object := p_selected_objects;
                /search_cycle_objects/
                  WHILE p_search_object <> NIL DO
                    IF (p_search_object^.entry.entry_type = puc$valid_cycle_entry) AND
                          p_search_object^.object_restored THEN
                      p_search_object := p_search_object^.link;
                      CYCLE /search_cycle_objects/;
                    IFEND;
                    pup$compare_item_descriptor (p_search_object^.entry, p_search_object^.p_catalog_header^,
                          p_item_description^.pf_utility_entry, p_item_description^.catalog_header,
                          local_entry_found, local_requested_subset_found);
                    IF local_entry_found THEN
                      restore_entry := TRUE;
                      p_current_object := p_search_object;
                      new_entry := found_entry;
                      PUSH p_selected_cycles: [1 .. 1];
                      p_selected_cycles ^[1] := p_search_object^.selected_cycle_info;
                      EXIT /search_cycle_objects/
                    ELSEIF local_requested_subset_found THEN
                      IF p_search_object^.entry.entry_type = puc$valid_pf_entry THEN
                        IF p_search_object^.selected_cycle_info.selected_cycle.cycle_specified THEN
                          IF (p_search_object^.selected_cycle_info.selected_cycle.cycle_selector.
                                cycle_option = pfc$specific_cycle) AND
                                (p_search_object^.selected_cycle_info.selected_cycle.cycle_selector.
                                cycle_number = p_item_description^.pf_utility_entry.pf_selector.
                                cycle_selector.cycle_number) THEN
                            p_search_object^.object_restored := TRUE;
                          IFEND;
                        ELSEIF NOT p_search_object^.selected_cycle_info.new_selected_cycle.cycle_specified
                              THEN
                          restore_entry := TRUE;
                          p_current_object := p_search_object;
                          new_entry := found_entry;
                          EXIT /search_cycle_objects/
                        IFEND;
                      ELSEIF p_search_object^.entry.entry_type = puc$valid_cycle_entry THEN
                        restore_entry := TRUE;
                        p_current_object := p_search_object;
                        new_entry := p_current_object^.new_entry;
                        PUSH p_selected_cycles: [1 .. 1];
                        p_selected_cycles ^[1] := p_search_object^.selected_cycle_info;
                        EXIT /search_cycle_objects/
                      ELSE
                        restore_entry := TRUE;
                        p_current_object := p_search_object;
                        new_entry := found_entry;
                        PUSH p_selected_cycles: [1 .. 1];
                        p_selected_cycles ^[1].selected_cycle.cycle_specified := TRUE;
                        p_selected_cycles ^[1].selected_cycle.cycle_selector :=
                              p_item_description^.pf_utility_entry.pf_selector.cycle_selector;
                        p_selected_cycles ^[1].new_selected_cycle.cycle_specified := TRUE;
                        p_selected_cycles ^[1].new_selected_cycle.cycle_selector :=
                              p_item_description^.pf_utility_entry.pf_selector.cycle_selector;
                        EXIT/search_cycle_objects/
                      IFEND;
                    IFEND;
                    p_search_object := p_search_object^.link;
                  WHILEND /search_cycle_objects/;
                ELSE
                  restore_entry := TRUE;
                  new_entry := found_entry;
                IFEND;

                IF restore_entry THEN
                  p_current_object^.object_restored := TRUE;

                  restore_found_entry (p_current_object^.p_catalog_header^, {password_specified} FALSE,
                        {password} osc$null_name, p_item_description^.catalog_header, found_entry,
                        p_current_object^.p_new_catalog_header^, new_entry, p_selected_cycles, backup_file_id,
                        file_position, local_status);

                  IF local_status.normal THEN
                    IF p_current_object^.entry.entry_type = puc$valid_pf_entry THEN
                      IF p_cycle_entries <> NIL THEN
                        FOR cycle_index := 1 TO UPPERBOUND (p_cycle_entries^) DO
                          IF (p_cycle_entries^ [cycle_index].pf_selector.cycle_selector.cycle_option =
                                pfc$highest_cycle) OR
                                (p_cycle_entries^ [cycle_index].pf_selector.cycle_selector.cycle_option =
                                pfc$lowest_cycle) THEN
                            p_cycle_object := p_selected_objects;
                          /change_cycle_object/
                            WHILE p_cycle_object <> NIL DO
                              pup$compare_item_descriptor (p_cycle_object^.entry,
                                    p_cycle_object^.p_catalog_header^, p_cycle_entries^ [cycle_index],
                                    p_item_description^.catalog_header, local_entry_found,
                                    local_requested_subset_found);
                              IF (local_entry_found OR local_requested_subset_found) AND
                                    (p_cycle_object^.entry.entry_type = puc$valid_cycle_entry) THEN
                                p_cycle_object^.entry.pf_selector.cycle_selector :=
                                      p_selected_cycles ^[cycle_index].selected_cycle.cycle_selector;
                                p_cycle_object^.selected_cycle_info.selected_cycle.cycle_selector :=
                                      p_selected_cycles ^[cycle_index].selected_cycle.cycle_selector;
                                EXIT /change_cycle_object/;
                              IFEND;
                              p_cycle_object := p_cycle_object^.link;
                            WHILEND /change_cycle_object/;
                          IFEND;
                        FOREND;
                      IFEND;
                    ELSEIF p_current_object^.entry.entry_type = puc$valid_cycle_entry THEN
                      all_objects_restored := TRUE;
                      p_search_object := p_selected_objects;
                    /check_selected_objects/
                      WHILE p_search_object <> NIL DO
                        all_objects_restored := (all_objects_restored AND p_search_object^.object_restored);
                        IF NOT all_objects_restored THEN
                          EXIT /check_selected_objects/;
                        IFEND;
                        p_search_object := p_search_object^.link;
                      WHILEND /check_selected_objects/;
                      IF all_objects_restored THEN
                        FREE p_item_description;
                        RETURN;
                      IFEND;
                    IFEND;
                  IFEND;
                IFEND;
              ELSEIF all_objects_restored THEN
                FREE p_item_description;
                RETURN;
              IFEND;
            IFEND;
            FREE p_item_description;
          ELSE
            osp$set_status_abnormal (puc$pf_utility_id, pue$unexpected_item_requested, ' identifer',
                  status);
          IFEND;
        IFEND;

        pup$write_os_status (status, status);
        IF file_position = puc$mid_partition THEN
          pup$skip_logical_partition (backup_file_id, file_position, status);
        IFEND;
      IFEND;
    UNTIL NOT status.normal OR (file_position = puc$eoi);

    p_current_object := p_selected_objects;

  /locate_unprocessed_objects/
    WHILE p_current_object <> NIL DO
      IF NOT p_current_object^.object_restored THEN
        pup$set_object_abnormal(p_current_object, pue$object_not_restored, local_status);
        pup$write_os_status (local_status, local_status);
      IFEND;
      p_current_object := p_current_object^.link;
    WHILEND /locate_unprocessed_objects/;

  PROCEND pup$restore_selected_objects;

?? TITLE := '    [XDCL] pup$restore_sub_levels ', EJECT ??
*copyc puh$restore_sub_levels

  PROCEDURE [XDCL] pup$restore_sub_levels
   (    entry: put$entry;
        catalog_header: put$catalog_header;
        password_specified: boolean;
        password: pft$password;
        new_catalog_header: put$catalog_header;
        restore_n_levels: boolean;
        p_selected_cycles: ^array [1 .. *] of put$selected_cycle_info;
    VAR backup_file_id: put$file_identifier;
    VAR status: ost$status);

    VAR
      any_entry_found: boolean,
      cycle_entry: put$entry,
      entry_found: boolean,
      file_position: put$file_position,
      found_entry: put$entry,
      high_or_low_cycle_number: integer,
      local_status: ost$status,
      p_item_description: ^put$backup_item_descriptor,
      record_header: put$backup_file_record_header,
      requested_subset_found: boolean,
      stored_backup_file_version: put$backup_file_version_name;

    entry_found := FALSE;
    any_entry_found := FALSE;

  /loop_through_partitions/
    REPEAT
      pup$locate_valid_version (backup_file_id, stored_backup_file_version, file_position, status);
      IF status.normal AND (file_position <> puc$eoi) THEN
        pup$get_next_record_header (backup_file_id, record_header, file_position, status);
        IF status.normal THEN
          IF (record_header.kind = puc$backup_item_identifier) AND (record_header.size >= 1) THEN
            ALLOCATE p_item_description: [1 .. record_header.size];
            pup$get_item_descriptor (backup_file_id, p_item_description^, file_position, status);
            IF status.normal THEN
              found_entry := p_item_description^.pf_utility_entry;
              pup$compare_item_descriptor (entry, catalog_header, found_entry, p_item_description^.
                    catalog_header, entry_found, requested_subset_found);
              IF requested_subset_found OR (entry_found AND restore_n_levels) THEN
                any_entry_found := (p_selected_cycles = NIL) OR
                      ((p_selected_cycles <> NIL) AND
                      (NOT p_selected_cycles^ [1].selected_cycle.cycle_specified) AND
                      (NOT p_selected_cycles^ [1].new_selected_cycle.cycle_specified));
                IF NOT entry_found AND NOT restore_n_levels AND
                      (found_entry.entry_type = puc$valid_pf_entry) AND
                      (UPPERBOUND (p_item_description^.catalog_header.path) = 3) THEN
                  pup$write_sub_path (p_item_description^.catalog_header.path,
                        LOWERBOUND (p_item_description^.catalog_header.path),
                        UPPERBOUND (p_item_description^.catalog_header.path) - 1, status);
                IFEND;
                restore_found_entry (catalog_header, password_specified, password,
                      p_item_description^.catalog_header, found_entry, new_catalog_header, found_entry,
                      p_selected_cycles, backup_file_id, file_position, local_status);
                IF local_status.normal AND (p_selected_cycles <> NIL) AND
                      (found_entry.entry_type = puc$valid_cycle_entry) AND
                      (p_selected_cycles^ [1].selected_cycle.cycle_selector.cycle_number =
                      found_entry.pf_selector.cycle_selector.cycle_number) THEN
                  any_entry_found := TRUE;
                  FREE p_item_description;
                  EXIT /loop_through_partitions/;
                IFEND;
              IFEND;
            IFEND;
            FREE p_item_description;
          ELSE
            osp$set_status_abnormal (puc$pf_utility_id, pue$unexpected_item_requested, ' identifer', status);
          IFEND;
        IFEND;
        pup$write_os_status (status, status);
        IF file_position = puc$mid_partition THEN
          pup$skip_logical_partition (backup_file_id, file_position, status);
        IFEND;
      IFEND;
    UNTIL NOT status.normal OR (file_position = puc$eoi);
    IF status.normal AND (NOT any_entry_found) THEN
      IF (p_selected_cycles <> NIL) AND ((p_selected_cycles^ [1].selected_cycle.cycle_specified) OR
            (p_selected_cycles^ [1].new_selected_cycle.cycle_specified)) THEN
        cycle_entry.entry_type := puc$valid_cycle_entry;
        cycle_entry.pf_selector.pfn := entry.pfn;
        cycle_entry.pf_selector.cycle_selector :=
              p_selected_cycles^ [1].selected_cycle.cycle_selector;
        pup$set_abnormal_entry_status (cycle_entry, pue$no_restore_no_find, status);
      ELSE
        pup$set_abnormal_entry_status (entry, pue$no_restore_no_find, status);
      IFEND;
    IFEND;
  PROCEND pup$restore_sub_levels;

?? TITLE := '    check_included_volumes ', EJECT ??

  PROCEDURE check_included_volumes
   (    file_reference: fst$path;
    VAR cycle_included: boolean;
    VAR status: ost$status);

    VAR
      catalog_depth: fst$catalog_depth,
      include_index: ost$positive_integers,
      information_request: fst$goi_information_request,
      object_info: ^fst$goi_object_information,
      object_info_sequence: ^SEQ (*),
      object_info_sequence_size: ost$positive_integers,
      p_volume_list: ^rmt$volume_list,
      volume_index: ost$positive_integers;

    IF puv$p_included_volumes = NIL THEN
      cycle_included := TRUE;
      RETURN;
    ELSE
      cycle_included := FALSE;
    IFEND;

    information_request.catalog_depth.depth_specification := fsc$specific_depth;
    information_request.catalog_depth.depth := 1;
    information_request.object_information_requests := $fst$goi_object_info_requests
          [fsc$goi_cycle_device_info];
    object_info_sequence_size := #SIZE (fst$goi_object_information) + fsc$max_path_size +
          #SIZE (fst$goi_object) + #SIZE (fst$device_information);
    PUSH object_info_sequence: [[REP object_info_sequence_size OF cell]];
    pfp$get_object_information (file_reference, information_request, {p_validation_criteria} NIL,
          object_info_sequence, status);
    IF status.normal THEN
      RESET object_info_sequence;
      NEXT object_info IN object_info_sequence;
      IF object_info^.object^.cycle_device_information^.mass_storage_device_info.resides_online THEN
        p_volume_list := object_info^.object^.cycle_device_information^.mass_storage_device_info.volume_list;
        IF p_volume_list <> NIL THEN
          FOR volume_index := LOWERBOUND (p_volume_list^) TO UPPERBOUND (p_volume_list^) DO
            FOR include_index := LOWERBOUND (puv$p_included_volumes^) TO
                  UPPERBOUND (puv$p_included_volumes^) DO
              IF p_volume_list^ [volume_index].recorded_vsn = puv$p_included_volumes^ [include_index] THEN
                cycle_included := TRUE;
                RETURN;
              IFEND;
            FOREND;
          FOREND;
        IFEND;
      IFEND;
    IFEND;

  PROCEND check_included_volumes;

?? TITLE := '    put_cycle_list_from_file_info ', EJECT ??

  PROCEDURE put_cycle_list_from_file_info
   (    file_info: pft$p_info_record;
        file_path: pft$path;
        password_selector: pft$password_selector;
        restore_archive_information: boolean;
        p_selected_cycles: ^array [1 .. *] of put$selected_cycle_info;
    VAR number_of_cycles_put: integer);

    VAR
      archive_identification: pft$archive_identification,
      archive_modification_date_time: ost$date_time,
      backup_file_cycle_selector: pft$cycle_selector,
      catalog_cycle_selector: pft$cycle_selector,
      comparison_result: pmt$comparison_result,
      cycle_array_entry: pft$cycle_array_entry_version_2,
      cycle_damage_symptoms: fst$cycle_damage_symptoms,
      cycle_included: boolean,
      cycle_index: integer,
      file_reference: fst$path,
      fs_path: fst$path,
      fs_path_size: fst$path_size,
      high_index: integer,
      highest_cycle_number: fst$cycle_number,
      i: integer,
      ignore_status: ost$status,
      local_status: ost$status,
      low_index: integer,
      lowest_cycle_number: fst$cycle_number,
      modification_date_time_found: boolean,
      new_access_date_time: fst$date_time,
      new_modification_date_time: fst$date_time,
      p_archive_entry: pft$p_archive_array_entry,
      p_archive_group: pft$p_info_record,
      p_archive_info: pft$p_info_record,
      p_archive_list_body: pft$p_info,
      p_archive_media: pft$p_amd,
      p_cycle_info_record: pft$p_info_record,
      p_cycle_list_version_1: pft$p_cycle_array,
      p_cycle_list_version_2: ^pft$cycle_array_version_2,
      p_cycle_media_description: pft$p_file_media_description,
      restored_file_cycle_selector: pft$cycle_selector;

    number_of_cycles_put := 0;
    IF p_selected_cycles = NIL THEN
     RETURN;
    IFEND;

    pfp$find_cycle_array_extended (file_info, p_cycle_array_extended_record, local_status);
    IF local_status.normal THEN
      pfp$find_cycle_directory (p_cycle_array_extended_record, p_cycle_directory_array, local_status);
      IF local_status.normal THEN
        IF puv$respf_backup_file_version = puc$backup_file_version_1 THEN
          pfp$find_cycle_array (file_info, p_cycle_list_version_1, local_status);
        ELSEIF puv$respf_backup_file_version = puc$backup_file_version_2 THEN
          pfp$find_cycle_array_version_2 (file_info, p_cycle_list_version_2, local_status);
        IFEND;
        IF local_status.normal AND (((puv$respf_backup_file_version = puc$backup_file_version_1) AND
              (p_cycle_list_version_1 <> NIL)) OR
              ((puv$respf_backup_file_version = puc$backup_file_version_2) AND
              (p_cycle_list_version_2 <> NIL))) THEN
          IF puv$respf_backup_file_version = puc$backup_file_version_1 THEN
            low_index := LOWERBOUND (p_cycle_list_version_1^);
            high_index := UPPERBOUND (p_cycle_list_version_1^);
          ELSEIF puv$respf_backup_file_version = puc$backup_file_version_2 THEN
            low_index := LOWERBOUND (p_cycle_list_version_2^);
            high_index := UPPERBOUND (p_cycle_list_version_2^);
          IFEND;

          IF puv$respf_backup_file_version = puc$backup_file_version_1 THEN
            lowest_cycle_number := p_cycle_list_version_1^ [low_index].cycle_number;
            highest_cycle_number := p_cycle_list_version_1^ [low_index].cycle_number;
          ELSEIF puv$respf_backup_file_version = puc$backup_file_version_2 THEN
            lowest_cycle_number := p_cycle_list_version_2^ [low_index].cycle_number;
            highest_cycle_number := p_cycle_list_version_2^ [low_index].cycle_number;
          IFEND;

          FOR i := low_index TO high_index DO
            IF puv$respf_backup_file_version = puc$backup_file_version_1 THEN
              IF p_cycle_list_version_1^ [i].cycle_number > highest_cycle_number THEN
                highest_cycle_number := p_cycle_list_version_1^ [i].cycle_number;
              IFEND;
              IF p_cycle_list_version_1^ [i].cycle_number < lowest_cycle_number THEN
                lowest_cycle_number := p_cycle_list_version_1^ [i].cycle_number;
              IFEND;
            ELSEIF puv$respf_backup_file_version = puc$backup_file_version_2 THEN
              IF p_cycle_list_version_2^ [i].cycle_number > highest_cycle_number THEN
                highest_cycle_number := p_cycle_list_version_2^ [i].cycle_number;
              IFEND;
              IF p_cycle_list_version_2^ [i].cycle_number < lowest_cycle_number THEN
                lowest_cycle_number := p_cycle_list_version_2^ [i].cycle_number;
              IFEND;
            IFEND;
          FOREND;

        /selected_cycles_loop/
          FOR cycle_index := 1 TO UPPERBOUND (p_selected_cycles^) DO
            backup_file_cycle_selector.cycle_option := pfc$specific_cycle;
            IF p_selected_cycles^ [cycle_index].selected_cycle.cycle_specified THEN
              IF p_selected_cycles^ [cycle_index].selected_cycle.cycle_selector.cycle_option =
                    pfc$specific_cycle THEN
                backup_file_cycle_selector.cycle_number :=
                      p_selected_cycles^ [cycle_index].selected_cycle.cycle_selector.cycle_number;
              ELSEIF p_selected_cycles^ [cycle_index].selected_cycle.cycle_selector.cycle_option =
                    pfc$lowest_cycle THEN
                backup_file_cycle_selector.cycle_number := lowest_cycle_number;
              ELSEIF p_selected_cycles^ [cycle_index].selected_cycle.cycle_selector.cycle_option =
                    pfc$highest_cycle THEN
                backup_file_cycle_selector.cycle_number := highest_cycle_number;
              IFEND;
              p_selected_cycles^ [cycle_index].selected_cycle.cycle_selector :=
                    backup_file_cycle_selector;
            IFEND;

          /specific_cycle_loop/
            FOR i := low_index TO high_index DO
              IF p_selected_cycles^ [cycle_index].selected_cycle.cycle_specified OR
                    p_selected_cycles^ [cycle_index].new_selected_cycle.cycle_specified THEN
                IF ((puv$respf_backup_file_version = puc$backup_file_version_1) AND
                      (backup_file_cycle_selector.cycle_number <> p_cycle_list_version_1^ [i].cycle_number))
                      THEN
                  CYCLE /specific_cycle_loop/;
                ELSEIF ((puv$respf_backup_file_version = puc$backup_file_version_2) AND
                      (backup_file_cycle_selector.cycle_number <> p_cycle_list_version_2^ [i].cycle_number))
                      THEN
                  CYCLE /specific_cycle_loop/;
                IFEND;
              ELSE
                IF puv$respf_backup_file_version = puc$backup_file_version_1 THEN
                  backup_file_cycle_selector.cycle_number := p_cycle_list_version_1^ [i].cycle_number;
                ELSEIF puv$respf_backup_file_version = puc$backup_file_version_2 THEN
                  backup_file_cycle_selector.cycle_number := p_cycle_list_version_2^ [i].cycle_number;
                IFEND;
              IFEND;

              pup$find_cycle_info_record (p_cycle_array_extended_record, p_cycle_directory_array,
                    backup_file_cycle_selector.cycle_number, ^file_path, p_cycle_info_record, local_status);
              IF local_status.normal THEN
                pfp$find_cycle_media (p_cycle_info_record, p_cycle_media_description, local_status);
                IF (NOT local_status.normal) AND (local_status.condition = pfe$unknown_cycle_media) THEN
                  local_status.normal := TRUE;
                  IF NOT restore_archive_information THEN
                    {
                    {  Do not write the cycle array entry if neither archive information nor data are to
                    {  be restored.
                    {
                    CYCLE /specific_cycle_loop/;
                  IFEND;
                IFEND;
              IFEND;
              IF NOT local_status.normal THEN
                pup$write_os_status (local_status, local_status);
                RETURN;
              IFEND;
              IF puv$respf_backup_file_version = puc$backup_file_version_1 THEN
                cycle_array_entry.bytes_allocated := 0;
                cycle_array_entry.cycle_damage_symptoms := $fst$cycle_damage_symptoms [];
                IF p_selected_cycles^ [cycle_index].new_selected_cycle.cycle_specified THEN
                  cycle_array_entry.cycle_number :=
                        p_selected_cycles^ [cycle_index].new_selected_cycle.cycle_selector.cycle_number;
                ELSE
                  cycle_array_entry.cycle_number := p_cycle_list_version_1^ [i].cycle_number;
                IFEND;
                cycle_array_entry.cycle_statistics := p_cycle_list_version_1^ [i].cycle_statistics;
                cycle_array_entry.data_modification_date_time :=
                      p_cycle_list_version_1^ [i].cycle_statistics.modification_date_time;
                cycle_array_entry.data_residence := pfc$unreleasable_data;
                cycle_array_entry.device_class := rmc$mass_storage_device;
                cycle_array_entry.eoi := 0;
                cycle_array_entry.expiration_date_time :=p_cycle_list_version_1^ [i].expiration_date_time;
                cycle_array_entry.original_unique_name := puv$null_original_unique_name;
                cycle_array_entry.retrieve_option := pfc$always_retrieve;
                cycle_array_entry.shared_queue_info.defined := FALSE;
                cycle_array_entry.site_archive_option := pfc$null_site_archive_option;
                cycle_array_entry.site_backup_option := pfc$null_site_backup_option;
                cycle_array_entry.site_release_option := pfc$null_site_release_option;
                cycle_array_entry.sparse_allocation := FALSE;
                cycle_array_entry.reserved_cycle_array_entry_sp := puv$null_res_cycle_array_ent_sp;
              ELSEIF puv$respf_backup_file_version = puc$backup_file_version_2 THEN
                cycle_array_entry := p_cycle_list_version_2^ [i];
                IF p_selected_cycles^ [cycle_index].new_selected_cycle.cycle_specified THEN
                  cycle_array_entry.cycle_number :=
                        p_selected_cycles^ [cycle_index].new_selected_cycle.cycle_selector.cycle_number;
                  cycle_array_entry.retrieve_option := pfc$always_retrieve;
                  cycle_array_entry.site_archive_option := pfc$null_site_archive_option;
                  cycle_array_entry.site_backup_option := pfc$null_site_backup_option;
                  cycle_array_entry.site_release_option := pfc$null_site_release_option;
                IFEND;
              IFEND;
              catalog_cycle_selector.cycle_option := pfc$specific_cycle;
              catalog_cycle_selector.cycle_number := cycle_array_entry.cycle_number;
              pup$check_cycle_access (cycle_array_entry, cycle_included);
              IF cycle_included THEN
                IF (puv$mass_storage_info.shared_queue <> pfc$null_shared_queue) AND
                      (cycle_array_entry.device_class = rmc$mass_storage_device) THEN
                  cycle_array_entry.shared_queue_info.defined := TRUE;
                  cycle_array_entry.shared_queue_info.shared_queue := puv$mass_storage_info.shared_queue;
                IFEND;
                IF NOT puv$create_objects THEN
                  pup$validate_n_n_minus_1 (file_path, puc$valid_cycle_entry, catalog_cycle_selector,
                        local_status);
                  IF (local_status.normal) OR ((NOT local_status.normal) AND
                        (local_status.condition = pue$restore_cycle_requires_file)) THEN
                    local_status.normal := TRUE;
                    CYCLE /specific_cycle_loop/
                  IFEND;
                IFEND;

                pfp$put_cycle_info (file_path, catalog_cycle_selector, password_selector, cycle_array_entry,
                      local_status);
                IF local_status.normal THEN
                  IF restore_archive_information THEN
                    pfp$put_archive_info (file_path, catalog_cycle_selector, p_cycle_info_record,
                          local_status);
                  IFEND;
                ELSEIF puv$replace_cycle_data AND ((local_status.condition = pfe$duplicate_cycle) OR
                      (local_status.condition = pfe$duplicate_offline_cycle)) THEN
                    {  If the backup file contains archive info, replace the
                    {  online data with the archive info. Make sure there is
                    {  archive info on the backup file before the online data
                    {  is deleted.
                  pfp$find_archive_info (p_cycle_info_record, p_archive_info, local_status);
                  IF local_status.normal AND restore_archive_information THEN
                    fsp$build_file_ref_from_elems (^file_path, file_reference, local_status);
                    IF local_status.normal THEN
                      check_included_volumes (file_reference, cycle_included, local_status);
                      IF local_status.normal AND cycle_included THEN
                        puv$purge_cycle_options.preserve_cycle_entry := puv$replace_cycle_data;
                        IF puv$purge_cycle_options.preserve_cycle_entry THEN
                          puv$purge_cycle_options.preserve_archive_info := FALSE;
                          puv$purge_cycle_options.preserve_file_label := FALSE;
                          puv$purge_cycle_options.preserve_modification_date_time := FALSE;
                        IFEND;
                        pfp$delete_cycle_data (file_path, catalog_cycle_selector, {password} osc$null_name,
                              puv$purge_cycle_options, local_status);
                        pfp$put_archive_info (file_path, catalog_cycle_selector, p_cycle_info_record,
                              local_status);
                        IF local_status.normal THEN
                          modification_date_time_found := FALSE;
                          archive_identification.application_identifier := osc$null_name;
                          archive_identification.media_identifier.media_device_class := osc$null_name;
                          archive_identification.media_identifier.media_volume_identifier := '';
                          p_archive_list_body := ^p_archive_info^.body;
                          REPEAT
                            pfp$find_next_archive_entry (archive_identification, p_archive_list_body,
                                  p_archive_group, p_archive_entry, p_archive_media, local_status);
                            IF local_status.normal THEN
                              IF modification_date_time_found THEN
                                pmp$date_time_compare (p_archive_entry^.archive_date_time,
                                       archive_modification_date_time, comparison_result, local_status);
                                IF comparison_result = pmc$left_is_greater THEN
                                  archive_modification_date_time :=
                                        p_archive_entry^.modification_date_time;
                                IFEND;
                              ELSE
                                modification_date_time_found := TRUE;
                                archive_modification_date_time := p_archive_entry^.modification_date_time;
                              IFEND;
                            IFEND;
                          UNTIL (p_archive_list_body = NIL) OR NOT local_status.normal;

                          IF modification_date_time_found THEN
                            new_access_date_time.value_specified := FALSE;
                            new_modification_date_time.value_specified := TRUE;
                            new_modification_date_time.date_time := archive_modification_date_time;
                            fsp$build_file_ref_from_elems (^file_path, file_reference, local_status);
                            fsp$change_cycle_date_time (file_reference, {password} osc$null_name,
                                      ^new_access_date_time, ^new_modification_date_time, local_status);
                          IFEND;
                        IFEND;
                      IFEND;
                    IFEND;
                  IFEND;
                IFEND;
                IF local_status.normal THEN
                  number_of_cycles_put := number_of_cycles_put + 1;
                ELSEIF (local_status.condition <> pfe$duplicate_cycle) AND
                      (local_status.condition <> pfe$duplicate_offline_cycle) THEN
                  RETURN;
                IFEND;
              IFEND;
            FOREND /specific_cycle_loop/;
          FOREND /selected_cycles_loop/;
        IFEND;
      ELSE
        p_cycle_array_extended_record := NIL;
      IFEND;
    ELSE
      p_cycle_array_extended_record := NIL;
    IFEND;
    IF (NOT local_status.normal) AND (local_status.condition <> pfe$duplicate_cycle) AND
          (local_status.condition <> pfe$duplicate_offline_cycle) THEN
      pup$write_os_status (local_status, local_status);
    IFEND;
  PROCEND put_cycle_list_from_file_info;

?? TITLE := '  restore_file_info', EJECT ??

  PROCEDURE restore_file_info
    (    new_online_cat_header: put$catalog_header;
         password_specified: boolean;
         password: pft$password;
         p_selected_cycles: {i/o} ^array [1 .. *] of put$selected_cycle_info;
     VAR backup_file_id: put$file_identifier;
     VAR file_position: put$file_position;
     VAR status: ost$status);

    VAR
      all_permits_restored: boolean,
      backup_file_version: pft$backup_file_version,
      cycle_index: integer,
      dummy_cycle_selector: pft$cycle_selector,
      fs_path: fst$path,
      fs_path_size: fst$path_size,
      ignore_status: ost$status,
      length: integer,
      listing_string: string (90),
      local_status: ost$status,
      number_of_cycles_put: integer,
      ownership: pft$ownership,
      p_cycle_array: pft$p_cycle_array,
      p_cycle_array_version_2: ^pft$cycle_array_version_2,
      p_file_description: pft$p_file_description,
      p_file_info_record: pft$p_info_record,
      p_local_selected_cycles: ^array [1 .. *] of put$selected_cycle_info,
      password_selector: pft$password_selector,
      put_cycle_list: boolean,
      record_header: put$backup_file_record_header,
      restore_archive_information: boolean,
      transfer_count: amt$file_length,
      variant_path: pft$variant_path;

    display (' entering restore_file_info');
    listing_string := '';
    listing_string (5, * ) := new_online_cat_header.path [UPPERBOUND (new_online_cat_header.path)];
    pup$display_line (listing_string, local_status);

    all_permits_restored := FALSE;
    put_cycle_list := FALSE;
    p_local_selected_cycles := p_selected_cycles;

    pup$get_next_record_header (backup_file_id, record_header, file_position, status);
    IF status.normal THEN
      IF (file_position = puc$mid_partition) AND (record_header.kind = puc$backup_file_info) AND
            (record_header.size > 0) THEN
        PUSH p_file_info_record: [[REP record_header.size OF cell]];
        pup$get_part (backup_file_id, p_file_info_record, #SIZE (p_file_info_record^), file_position,
              transfer_count, status);
      ELSE
        osp$set_status_abnormal (puc$pf_utility_id, pue$unusable_restore_file, ' info ', status);
      IFEND;
    IFEND;

    IF status.normal THEN
      restore_archive_information := puv$restore_archive_information;
      IF avp$family_administrator() AND (NOT avp$system_administrator()) THEN
        variant_path.complete_path := FALSE;
        variant_path.p_path := ^new_online_cat_header.path;
        pfp$get_ownership (variant_path, {system_privilege} TRUE, ownership, status);
        IF NOT status.normal OR (NOT (pfc$family_owner IN ownership)) THEN
          restore_archive_information := FALSE;
          osp$set_status_abnormal (puc$pf_utility_id, pue$archive_info_not_restored,
                'you are not the family administrator', local_status);
          pup$write_os_status (local_status, ignore_status);
        IFEND
      IFEND;

      IF puv$trace_selected THEN
        pup$display_boolean (' puv$restore_archive_information = ', puv$restore_archive_information,
              local_status);
        pup$display_boolean (' restore_archive_information = ', restore_archive_information, local_status);
      IFEND;

      IF (p_selected_cycles = NIL) OR ((p_selected_cycles <> NIL) AND
            (NOT p_selected_cycles^ [1].selected_cycle.cycle_specified) AND
            (NOT p_selected_cycles^ [1].new_selected_cycle.cycle_specified)) THEN
        display (' pfp$put_item_info');

        IF puv$respf_backup_file_version = puc$backup_file_version_1 THEN
          backup_file_version := pfc$backup_file_version_1;
          pfp$find_cycle_array (p_file_info_record, p_cycle_array, status);
          IF NOT status.normal THEN
            p_cycle_array := NIL;
          IFEND;
        ELSEIF puv$respf_backup_file_version = puc$backup_file_version_2 THEN
          backup_file_version := pfc$backup_file_version_2;
          pfp$find_cycle_array_version_2 (p_file_info_record, p_cycle_array_version_2, status);
          IF NOT status.normal THEN
            p_cycle_array_version_2 := NIL;
          IFEND;
        IFEND;

        IF (backup_file_version = pfc$backup_file_version_2) AND (p_cycle_array_version_2 <> NIL) THEN
          FOR cycle_index := LOWERBOUND (p_cycle_array_version_2^) TO
                UPPERBOUND (p_cycle_array_version_2^) DO
            IF (puv$mass_storage_info.shared_queue <> pfc$null_shared_queue) AND
                  (p_cycle_array_version_2^ [cycle_index].device_class = rmc$mass_storage_device) THEN
              p_cycle_array_version_2^ [cycle_index].shared_queue_info.defined := TRUE;
              p_cycle_array_version_2^ [cycle_index].shared_queue_info.shared_queue :=
                    puv$mass_storage_info.shared_queue;
            IFEND;
          FOREND;
        IFEND;

        IF NOT puv$create_objects THEN
          pup$validate_n_n_minus_1 (new_online_cat_header.path, puc$valid_pf_entry, dummy_cycle_selector,
                local_status);
          IF local_status.normal THEN
            pup$display_line (
                  'File cannot be created when FALSE is specified for the CREATE_OBJECTS parameter',
                  ignore_status);
            RETURN;
          IFEND;
        IFEND;

        pfp$put_item_info (new_online_cat_header.path, p_file_info_record, restore_archive_information,
              puv$backup_criteria, backup_file_version, all_permits_restored, status);
        IF puv$trace_selected THEN
          display_status (status);
        IFEND;
        IF (NOT status.normal) AND (status.condition = pfe$name_already_permanent_file) THEN

{       If the file exists and there are some cycles without data, (i.e OFFLINE)
{       construct the p_selected_cycles array to restore the cycle_entries.

          status.normal := TRUE;
          IF backup_file_version = pfc$backup_file_version_1 THEN
            IF p_cycle_array <> NIL THEN
              PUSH p_local_selected_cycles: [1 .. UPPERBOUND (p_cycle_array^)];
              FOR cycle_index := LOWERBOUND (p_cycle_array^) TO
                    UPPERBOUND (p_cycle_array^) DO
                p_local_selected_cycles^ [cycle_index].selected_cycle.cycle_specified := TRUE;
                p_local_selected_cycles^ [cycle_index].selected_cycle.cycle_selector.cycle_option :=
                      pfc$specific_cycle;
                p_local_selected_cycles^ [cycle_index].selected_cycle.cycle_selector.cycle_number :=
                      p_cycle_array^ [cycle_index].cycle_number;
              FOREND;
              put_cycle_list := TRUE;
            IFEND;
          ELSEIF  backup_file_version = pfc$backup_file_version_2 THEN
            IF p_cycle_array_version_2 <> NIL THEN
              PUSH p_local_selected_cycles: [1 .. UPPERBOUND (p_cycle_array_version_2^)];
              FOR cycle_index := LOWERBOUND (p_cycle_array_version_2^) TO
                    UPPERBOUND (p_cycle_array_version_2^) DO
                p_local_selected_cycles^ [cycle_index].selected_cycle.cycle_specified := TRUE;
                p_local_selected_cycles^ [cycle_index].selected_cycle.cycle_selector.cycle_option :=
                      pfc$specific_cycle;
                p_local_selected_cycles^ [cycle_index].selected_cycle.cycle_selector.cycle_number :=
                      p_cycle_array_version_2^ [cycle_index].cycle_number;
              FOREND;
              put_cycle_list := TRUE;
            IFEND;
          IFEND;
        IFEND;
        IF NOT all_permits_restored THEN
          osp$set_status_abnormal (puc$pf_utility_id, pue$not_all_permits_restored, 'file', local_status);
          pup$write_os_status (local_status, ignore_status);
        IFEND;
      ELSE
        put_cycle_list := TRUE;
      IFEND;
    IFEND;

    IF status.normal THEN
      IF puc$cdo_alternate_storage IN puv$cycle_display_selections THEN
        pfp$find_cycle_array_extended (p_file_info_record, p_cycle_array_extended_record, status);
        IF status.normal THEN
          pfp$find_cycle_directory (p_cycle_array_extended_record, p_cycle_directory_array, status);
        IFEND;
        IF NOT status.normal THEN
          p_cycle_array_extended_record := NIL;
          pup$write_os_status (status, local_status);
          status.normal := TRUE;
        IFEND;
      IFEND;
    IFEND;

    IF put_cycle_list THEN
      IF password_specified THEN
        password_selector.password_specified := pfc$specific_password_option;
        password_selector.password := password;
      ELSE
        pfp$find_file_description (p_file_info_record, p_file_description, local_status);
        IF local_status.normal THEN
          password_selector.password_specified := pfc$specific_password_option;
          password_selector.password := p_file_description^.password;
        ELSE
          password_selector.password_specified := pfc$default_password_option;
        IFEND;
      IFEND;
      put_cycle_list_from_file_info (p_file_info_record, new_online_cat_header.path, password_selector,
            restore_archive_information, p_local_selected_cycles, number_of_cycles_put);
      IF ((p_selected_cycles = NIL) OR ((p_selected_cycles <> NIL) AND
            (NOT p_selected_cycles^ [1].selected_cycle.cycle_specified) AND
            (NOT p_selected_cycles^ [1].new_selected_cycle.cycle_specified))) AND
            (number_of_cycles_put > 0) THEN
        STRINGREP (listing_string, length, '    -- FILE ALREADY EXISTS: ', number_of_cycles_put,
              '  CYCLE ENTRIES RESTORED');
        pup$display_line (listing_string (1, length), local_status);
      IFEND;
    IFEND;

    IF (NOT puv$replace_cycle_data) OR ((NOT status.normal) AND
          (status.condition <> pfe$duplicate_cycle)) THEN
      pup$write_os_status (status, local_status);
    IFEND;
    display (' leaving restore_file_info');

  PROCEND restore_file_info;

?? TITLE := '    restore_found_entry ', EJECT ??

  PROCEDURE restore_found_entry
   (    catalog_header: put$catalog_header;
        password_specified: boolean;
        password: pft$password;
        found_catalog_header: put$catalog_header;
        found_entry: put$entry;
        new_catalog_header: put$catalog_header;
        new_entry: put$entry;
        p_selected_cycles: {i/o} ^array [1 .. *] of put$selected_cycle_info;
    VAR backup_file_id: put$file_identifier;
    VAR file_position: put$file_position;
    VAR status: ost$status);

{  The purpose of this routine is to "process" a found entry.  This includes:
{  build a new online path
{     restore the item (PF will return bad status if item exists)

    VAR
      cycle_selector: pft$cycle_selector,
      ignore_status: ost$status,
      item_type: put$entry_type,
      listing_string: string (90),
      local_status: ost$status,
      new_online_path_length: integer,
      p_new_online_catalog_header: ^put$catalog_header,
      password_selector: pft$password_selector;

    new_online_path_length := pup$physical_path_length (new_catalog_header.logical_path_length +
          found_catalog_header.logical_path_length - catalog_header.logical_path_length);
    PUSH p_new_online_catalog_header: [1 .. new_online_path_length];
    pup$build_new_online_cat_head (catalog_header, new_catalog_header, found_catalog_header,
          p_new_online_catalog_header^);

    CASE found_entry.entry_type OF
    = puc$valid_set_entry =
    = puc$valid_family_entry =
      IF puv$create_objects THEN
        pup$restore_catalog_info (p_new_online_catalog_header^, backup_file_id, file_position, status);
      ELSE
        pup$write_path (p_new_online_catalog_header^.path, ignore_status);
        pup$display_line ('Family cannot be created when FALSE is specified for the CREATE_OBJECTS parameter',
              ignore_status);
        pup$display_blank_lines (1, ignore_status);
      IFEND;
    = puc$valid_catalog_entry =
      IF puv$create_objects THEN
        pup$restore_catalog_info (p_new_online_catalog_header^, backup_file_id, file_position, status);
      ELSE
        pup$write_path (p_new_online_catalog_header^.path, ignore_status);
        pup$verify_catalog_path (p_new_online_catalog_header^.path, local_status);
        IF local_status.normal THEN
          pup$display_line ('    -- CATALOG ALREADY EXISTS', ignore_status);
        ELSE
          pup$display_line (
                'Catalog cannot be created when FALSE is specified for the CREATE_OBJECTS parameter',
                ignore_status);
          pup$display_blank_lines (1, ignore_status);
        IFEND;
      IFEND;
    = puc$valid_pf_entry =
      puv$purge_cycle_options.preserve_cycle_entry := puv$replace_cycle_data;
      IF puv$purge_cycle_options.preserve_cycle_entry THEN
        puv$purge_cycle_options.preserve_archive_info := FALSE;
        puv$purge_cycle_options.preserve_file_label := FALSE;
        puv$purge_cycle_options.preserve_modification_date_time := FALSE;
      IFEND;
      restore_file_info (p_new_online_catalog_header^, password_specified, password, p_selected_cycles,
              backup_file_id, file_position, status);
    = puc$valid_cycle_entry =
      IF password_specified THEN
        password_selector.password_specified := pfc$specific_password_option;
        password_selector.password := password;
      ELSE
        password_selector.password_specified := pfc$default_password_option;
      IFEND;

      puv$purge_cycle_options.preserve_cycle_entry := puv$replace_cycle_data;
      IF puv$purge_cycle_options.preserve_cycle_entry THEN
        puv$purge_cycle_options.preserve_archive_info := TRUE;
        puv$purge_cycle_options.preserve_file_label := TRUE;
        puv$purge_cycle_options.preserve_modification_date_time := TRUE;
      IFEND;

      cycle_selector.cycle_option := pfc$specific_cycle;
      IF (p_selected_cycles = NIL) OR ((p_selected_cycles <> NIL) AND
            (NOT p_selected_cycles^ [1].selected_cycle.cycle_specified) AND
            (NOT p_selected_cycles^ [1].new_selected_cycle.cycle_specified)) THEN
        cycle_selector.cycle_number := new_entry.pf_selector.cycle_selector.cycle_number;
        pup$restore_cycle_item (found_entry, p_new_online_catalog_header^.path, cycle_selector,
              password_selector, p_cycle_array_extended_record, p_cycle_directory_array, backup_file_id,
              file_position, status);
      ELSE
        IF p_selected_cycles^ [1].selected_cycle.cycle_selector.cycle_number =
              found_entry.pf_selector.cycle_selector.cycle_number THEN
          IF p_selected_cycles^ [1].new_selected_cycle.cycle_specified THEN
            cycle_selector.cycle_number :=
                  p_selected_cycles^ [1].new_selected_cycle.cycle_selector.cycle_number;
          ELSE
            cycle_selector.cycle_number :=
                  p_selected_cycles^ [1].selected_cycle.cycle_selector.cycle_number;
          IFEND;
          pup$restore_cycle_item (found_entry, p_new_online_catalog_header^.path, cycle_selector,
                password_selector, p_cycle_array_extended_record, p_cycle_directory_array, backup_file_id,
                file_position, status);
        IFEND;
      IFEND;
    ELSE
      osp$set_status_abnormal (puc$pf_utility_id, pue$unexpected_item_requested, ' entry ', status);
      pup$write_os_status (status, local_status);
    CASEND;
  PROCEND restore_found_entry;

?? TITLE := '    validate_version_number ', EJECT ??

  PROCEDURE validate_version_number
   (    stored_backup_file_version_name: put$backup_file_version_name;
        backup_file_id: put$file_identifier;
    VAR status: ost$status);

    CONST
      number_of_supported_versions = 2,
      supported_version_str_len = 23,
      supported_versions_str_len = (number_of_supported_versions * supported_version_str_len) +
            ((number_of_supported_versions - 1) * 2);

    VAR
      backup_file_path: fst$path,
      backup_file_path_size: fst$path_size,
      ignore_path_handle: fmt$path_handle,
      local_status: ost$status,
      p_supported_version_names: ^array [1 .. number_of_supported_versions] of
            string (supported_version_str_len),
      p_supported_versions_str: ^string (supported_versions_str_len),
      supported_versions_str_len_var: integer;

    status.normal := TRUE;
    IF (stored_backup_file_version_name = puc$backup_file_version_1) OR
          (stored_backup_file_version_name = puc$backup_file_version_2) THEN
      puv$respf_backup_file_version := stored_backup_file_version_name;
    ELSE
      IF (stored_backup_file_version_name (1,20) = 'BACKUP_FILE_VERSION_') AND
         ('3' <= stored_backup_file_version_name (supported_version_str_len)) AND
            (stored_backup_file_version_name (supported_version_str_len) <= '9') THEN
        clp$get_fs_path_string (backup_file_id.lfn, backup_file_path, backup_file_path_size,
              ignore_path_handle, local_status);
        osp$set_status_abnormal (puc$pf_utility_id, pue$incompatible_backup_version,
              backup_file_path (1, backup_file_path_size), status);
        PUSH p_supported_version_names;
        p_supported_version_names^ [1] := puc$backup_file_version_1;
        p_supported_version_names^ [2] := puc$backup_file_version_2;
        PUSH p_supported_versions_str;
        STRINGREP (p_supported_versions_str^, supported_versions_str_len_var, p_supported_version_names^ [1],
              ', ', p_supported_version_names^ [2]);
        osp$append_status_parameter (osc$status_parameter_delimiter,
              p_supported_versions_str^ (1, supported_versions_str_len), status);
        osp$append_status_parameter (osc$status_parameter_delimiter, stored_backup_file_version_name,
              status);
      ELSE
        osp$set_status_abnormal (puc$pf_utility_id, pue$unable_to_read_version,
              stored_backup_file_version_name, status);
      IFEND;
    IFEND;
  PROCEND validate_version_number;

?? OLDTITLE, SKIP := 2 ??
MODEND pum$backup_file_input;
