?? RIGHT := 110 ??
?? NEWTITLE := 'INSTALL_SOFTWARE Utility: RAP$UPDATE_DIRECTORY Interface.' ??
MODULE ram$update_directory;

{ PURPOSE:
{   This module contains the interface and procedures that updates
{   the IDB directory to describe the current state of the installed
{   software.
{
{ DESIGN:
{   The compiled module resides in RAF$LIBRARY.
{
{ NOTES:
{

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc rae$install_software_cc
*copyc rac$idb_directory_level
*copyc rac$idb_directory_name
*copyc rac$inss_processor_version
*copyc rac$not_installed
*copyc rat$installation_control_record
*copyc rat$sequence_descriptor_types
?? POP ??
*copyc i#current_sequence_position
*copyc amp$fetch_access_information
*copyc amp$set_segment_eoi
*copyc clp$trimmed_string_size
*copyc fsp$close_file
*copyc fsp$open_file
*copyc osp$append_status_file
*copyc osp$append_status_parameter
*copyc osp$establish_block_exit_hndlr
*copyc osp$disestablish_cond_handler
*copyc osp$generate_log_message
*copyc osp$set_status_abnormal
*copyc pmp$get_compact_date_time
*copyc rap$access_directory_for_write
*copyc rap$clear_installation
*copyc rap$convert_path_to_str
*copyc rap$establish_directory_ptrs
*copyc rap$locate_directory_record
*copyc rap$record_step_status
*copyc rap$record_subproduct_status
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??

?? OLDTITLE ??
?? NEWTITLE := '[XDCL] rap$update_directory', EJECT ??

{ PURPOSE:
{   This interface controls the step to update the IDB directory.
{
{ DESIGN:
{   The IDB directory is updated to describe the current state of the
{   installed software.  More precisely, the subproduct information records
{   are set with the proper level data.
{
{   The IDB directory file is opened for write access mode, share mode of
{   none, if not found it will be created.  The directory is then copied to
{   a memory scratch segment where the changes are made.  If the update is
{   successuful the scratch directory is copied back over the IDB directory
{   file.
{
{   Generally, in step processing the failure of one subproduct will not
{   jeopardize the remaining subproducts.  Each subproduct is processed
{   independently.  But in updating the directory a failure of one
{   subproduct affects the remaining subproducts.
{
{ NOTES:
{   The SUBPRODUCTS_FAILED_PROCESSING boolean has been initialized outside of
{   this interface and should never be re-initialized here.
{

  PROCEDURE [XDCL] rap$update_directory
    (VAR installation_control_record {input} : rat$installation_control_record;
     VAR subproducts_failed_processing: boolean;
     VAR status: ost$status);


    VAR
      directory_fid: amt$file_identifier,
      directory_pointers: rat$idb_directory_pointers,
      directory_segment_pointer: amt$segment_pointer,
      file_opened: boolean,
      ignore_status: ost$status,
      local_status: ost$status;


?? NEWTITLE := 'abort_handler', EJECT ??

{ PURPOSE:
{   This procedure cleans up when an abort situation occurs within the
{   block structure.
{
{ DESIGN:
{   The function of this condition handler is to close the IDB directory
{   when an abort condition arises.
{
{ NOTES:
{

    PROCEDURE abort_handler
      (    condition: pmt$condition;
           condition_information: ^pmt$condition_information;
           save_area: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      VAR
        ignore_status: ost$status;

      fsp$close_file (directory_fid, ignore_status);

    PROCEND abort_handler;

?? OLDTITLE, EJECT ??


    status.normal := TRUE;
    file_opened := FALSE;

    IF NOT (rac$update_directory_step IN installation_control_record.processing_header_p^.step_set) THEN
      RETURN;
    IFEND;

    rap$record_step_status (rac$update_directory_step, rac$step_started, installation_control_record, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    osp$establish_block_exit_hndlr (^abort_handler);

  /main/
    BEGIN

      rap$access_directory_for_write (installation_control_record.processing_header_p^.installation_defaults.
            installation_database, directory_segment_pointer, directory_fid, file_opened, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      copy_directory_into_memory (directory_fid, directory_segment_pointer,
            installation_control_record.scratch_seq_p, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      { Pointers are established to the directory copy in memory.
      { The interface rap$establish_directory_ptrs uses the directory_pointers
      { sequence_p field to establish the rest of the directory pointers.  The
      { path to the installation database catalog is used for message templates
      { only.

      directory_pointers.sequence_p := installation_control_record.scratch_seq_p;

      rap$establish_directory_ptrs (installation_control_record.processing_header_p^.installation_defaults.
            installation_database, directory_pointers, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      update_directory_records (installation_control_record, directory_pointers,
            subproducts_failed_processing, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      write_idb_directory_file (directory_fid, directory_segment_pointer, directory_pointers.sequence_p,
            status);

    END /main/;

    IF file_opened THEN
      fsp$close_file (directory_fid, local_status);
      IF status.normal AND (NOT local_status.normal) THEN
        status := local_status;
      IFEND;
    IFEND;


    osp$disestablish_cond_handler;

    rap$clear_installation (installation_control_record, ignore_status);

    rap$record_step_status (rac$update_directory_step, rac$step_completed, installation_control_record,
          local_status);
    IF status.normal AND (NOT local_status.normal) THEN
      status := local_status;
    IFEND;

  PROCEND rap$update_directory;

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

{ PURPOSE:
{   This procedure combines the new directory records with the
{   directory array.  Once combined the directory is sorted by
{   the sort key field.
{
{ DESIGN:
{   The procedure uses a shell sort.
{
{   The sort key is a combination of the licensed product and
{   subproduct name fields.
{
{ NOTES:
{

  PROCEDURE combine_directory_records
    (    new_directory_record_count: rat$subproduct_count;
     VAR directory_pointers {input} : rat$idb_directory_pointers;
     VAR status: ost$status);


    VAR
      current: integer,
      directory_size: rat$subproduct_count,
      gap: integer,
      start: integer,
      swap: rat$directory_record;


    status.normal := TRUE;

    directory_size := directory_pointers.header_p^.directory_size + new_directory_record_count;

    RESET directory_pointers.sequence_p TO directory_pointers.directory_p;
    NEXT directory_pointers.directory_p: [1 .. directory_size] IN directory_pointers.sequence_p;
    IF directory_pointers.directory_p = NIL THEN
      osp$set_status_abnormal ('RA', rae$accessed_beyond_segment_eoi, 'IDB directory', status);
      osp$append_status_parameter (osc$status_parameter_delimiter, 'COMBINING DIRECTORY', status);
      RETURN;
    IFEND;

    directory_pointers.header_p^.directory_size := directory_size;
    directory_pointers.header_p^.directory_rel_p := #REL (directory_pointers.directory_p,
          directory_pointers.sequence_p^);

    { Sort the directory.

    gap := UPPERBOUND (directory_pointers.directory_p^);

    WHILE gap > 1 DO
      gap := 2 * (gap DIV 4) + 1;

      FOR start := LOWERBOUND (directory_pointers.directory_p^)
            TO UPPERBOUND (directory_pointers.directory_p^) - gap DO
        current := start;

        WHILE (current > 0) AND (directory_pointers.directory_p^ [current].sort_key >
              directory_pointers.directory_p^ [current + gap].sort_key) DO
          swap := directory_pointers.directory_p^ [current];
          directory_pointers.directory_p^ [current] := directory_pointers.directory_p^ [current + gap];
          directory_pointers.directory_p^ [current + gap] := swap;
          current := current - gap;
        WHILEND;

      FOREND;

    WHILEND;

  PROCEND combine_directory_records;

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

{ PURPOSE:
{   This procedure copies the IDB directory into a scratch memory sequence.
{
{ DESIGN:
{   The direcotry has already been opened for write access.  This causes the
{   end of file to be set far beyond actual EOI.  The actual EOI is
{   retrieved and used to calculate file content size.  This size is
{   reserved in the scratch sequence found in memory and the contents from
{   the directory are copied using a simple assignment statement.
{
{ NOTES:
{

  PROCEDURE copy_directory_into_memory
    (    directory_fid: amt$file_identifier;
     VAR directory_segment_pointer {input} : amt$segment_pointer;
     VAR scratch_seq_p: ^SEQ ( * );
     VAR status: ost$status);


    VAR
      access_information: array [1 .. 1] of amt$access_info,
      file_contents_p: ^rat$idb_directory_sequence,
      ignore_contains_data: boolean,
      ignore_status: ost$status,
      memory_contents_p: ^rat$idb_directory_sequence;


    status.normal := TRUE;

    access_information [1].key := amc$eoi_byte_address;
    amp$fetch_access_information (directory_fid, access_information, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    RESET directory_segment_pointer.sequence_pointer;
    NEXT file_contents_p: [[REP access_information [1].eoi_byte_address OF cell]] IN
          directory_segment_pointer.sequence_pointer;
    IF file_contents_p = NIL THEN
      osp$set_status_abnormal ('RA', rae$accessed_beyond_segment_eoi, 'IDB directory', status);
      osp$append_status_parameter (osc$status_parameter_delimiter, 'FILE SEQUENCE', status);
      RETURN;
    IFEND;

    RESET scratch_seq_p;
    NEXT memory_contents_p: [[REP access_information [1].eoi_byte_address OF cell]] IN scratch_seq_p;
    IF memory_contents_p = NIL THEN
      osp$set_status_abnormal ('RA', rae$accessed_beyond_segment_eoi, 'IDB directory', status);
      osp$append_status_parameter (osc$status_parameter_delimiter, 'MEMORY SEQUENCE', status);
      RETURN;
    IFEND;

    memory_contents_p^ := file_contents_p^;

  PROCEND copy_directory_into_memory;

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

{ PURPOSE:
{   This procedure initializes a new directory record for a subproduct.
{
{ DESIGN:
{   The record is added to the end of the directory sequence.  Later it will
{   be combined and sorted with the rest of the directory records.
{
{ NOTES:
{   Every field except the subproduct's name field will be set by another
{   procedure.
{

  PROCEDURE initialize_directory_record
    (    subproduct_attributes_p: ^rat$subproduct_attributes;
     VAR directory_record_p: ^rat$directory_record;
     VAR directory_sequence_p: ^rat$idb_directory_sequence;
     VAR new_directory_record_count: rat$subproduct_count;
     VAR status: ost$status);


    status.normal := TRUE;

    NEXT directory_record_p IN directory_sequence_p;
    IF directory_record_p = NIL THEN
      osp$set_status_abnormal ('RA', rae$accessed_beyond_segment_eoi, 'IDB directory', status);
      osp$append_status_parameter (osc$status_parameter_delimiter, 'NEW ENTRY', status);
      RETURN;
    IFEND;

    new_directory_record_count := new_directory_record_count + 1;

    { Initialize general data and installation identifiers.

    directory_record_p^.subproduct := subproduct_attributes_p^.name;
    directory_record_p^.licensed_product := subproduct_attributes_p^.licensed_product;
    directory_record_p^.primary_subproduct := subproduct_attributes_p^.primary;
    directory_record_p^.description := subproduct_attributes_p^.description;
    directory_record_p^.hidden := subproduct_attributes_p^.hidden;
    directory_record_p^.subproduct_corrupted := FALSE;
    directory_record_p^.base_level_installation_catalog.size := 0;
    directory_record_p^.system_catalog_path_index := 0;
    directory_record_p^.active_information.installation_identifier := rac$not_installed;
    directory_record_p^.deferred_information.installation_identifier := rac$not_installed;
    directory_record_p^.corrective_base_information.installation_identifier := rac$not_installed;

  PROCEND initialize_directory_record;

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

{ PURPOSE:
{   This procedure sets the main directory record fields for a subproduct of
{   type release.
{
{ DESIGN:
{   The subproduct is assumed to be of type release.  The setting of the
{   directory record fields are not very exciting except for the base level
{   installation catalog and system catalog index.
{
{   The installation catalog of a release subproduct is the base level
{   installation catalog for that subproduct.  The path must first be
{   reformated from PF to a string format.
{
{   The system catalog index locates that portion of the base level
{   installation catalog that is defined as the system catalog.  The index
{   is computed by analyzing the system catalog path size defined in the
{   installation defaults.  If the system catalog path size is not zero, the
{   default system catalog path was merged with the subproduct's
{   installation path to create the installation catalog path.  The system
{   catalog index is therefore the same as the default system catalog path
{   size.  Otherwise, the subproduct's installation path was taken as is for
{   the installation catalog path.  The system catalog index is the length
{   of the family and user catalogs combined.
{
{ NOTES:
{

  PROCEDURE set_directory_record
    (    subproduct_attributes_p: ^rat$subproduct_attributes;
         installation_catalog_p: ^pft$path;
         default_system_catalog_size: integer;
     VAR directory_record_p: ^rat$directory_record);


    VAR
      catalog_delimiter_count: 0 .. 2,
      index: integer;


    directory_record_p^.licensed_product := subproduct_attributes_p^.licensed_product;
    directory_record_p^.primary_subproduct := subproduct_attributes_p^.primary;
    directory_record_p^.description := subproduct_attributes_p^.description;
    directory_record_p^.hidden := subproduct_attributes_p^.hidden;

    rap$convert_path_to_str (installation_catalog_p^, directory_record_p^.base_level_installation_catalog);

    IF default_system_catalog_size <> 0 THEN
      directory_record_p^.system_catalog_path_index := default_system_catalog_size;
    ELSE

      { System catalog index is the end of the family and user catalogs on the
      { base level installation catalog path.

      index := 0;
      catalog_delimiter_count := 0;
      WHILE (index < directory_record_p^.base_level_installation_catalog.size) AND
            (catalog_delimiter_count < 2) DO
        index := index + 1;
        IF directory_record_p^.base_level_installation_catalog.path (index, 1) = '.' THEN
          catalog_delimiter_count := catalog_delimiter_count + 1;
        IFEND;
      WHILEND;


      IF catalog_delimiter_count < 2 THEN

        { The length of the system catalog path is the same as the
        { length of the base level installation catalog path.

        directory_record_p^.system_catalog_path_index := index;

      ELSE { catalog_delimiter_count = 2 }

        { The index is adjusted to remove the second catalog delimiter.
        { The adjusted value becomes the system catalog path index.

        directory_record_p^.system_catalog_path_index := index - 1;

      IFEND;
    IFEND;

  PROCEND set_directory_record;

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

{ PURPOSE:
{   This procedure sets the installation information record for the
{   subproduct.
{
{ DESIGN:
{   The installation information record can be one of three kinds:  active,
{   deferred, or corrective base.  The filling of these records is exactly
{   the same.
{
{ NOTES:
{

  PROCEDURE set_installation_information
    (    subproduct_index: rat$subproduct_count;
         date_installed: ost$date_time;
         processing_header_p: ^rat$processing_header;
         subproduct_attributes_p: ^rat$subproduct_attributes;
     VAR information_record: rat$information_record);


    information_record.date_installed := date_installed;
    information_record.installation_identifier := processing_header_p^.installation_identifier;
    information_record.subproduct_level := subproduct_attributes_p^.level;
    information_record.internal_level := subproduct_attributes_p^.internal_level;
    information_record.sif_identifier := subproduct_attributes_p^.sif_identifier;
    information_record.packing_list := processing_header_p^.packing_list_name;
    information_record.packing_list_index := subproduct_index;

  PROCEND set_installation_information;

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

{ PURPOSE:
{   This procedure updates the directory record for the current subproduct.
{
{ DESIGN:
{   The record is located in the directory, if not found a new record will
{   be added to the EOI of the directory sequence.  The required
{   information is then registered.
{
{   Later, in another procedure, the new directory records are combined
{   with the current directory array and sorted.
{
{ NOTES:
{   ** When the RAP$CLEAR_INSTALLATION interface is implemented we will be
{   able to protect any previous active level all the way up to executing
{   the installer procedure.  When there is no installer procedure we can
{   cleanly back out of the failed installation and protect any existing
{   active level.  The test to set the subproduct as corrupted will have
{   to be adjusted at that time.
{

  PROCEDURE update_directory_for_subproduct
    (    subproduct_index: rat$subproduct_count;
         date_installed: ost$date_time;
         last_task: rat$tasks;
         last_task_status: rat$task_status;
         processing_header_p: ^rat$processing_header;
         processing_record: rat$subp_processing_record;
     VAR directory_pointers {input} : rat$idb_directory_pointers;
     VAR new_directory_record_count: rat$subproduct_count;
     VAR status: ost$status);


    VAR
      directory_record_p: ^rat$directory_record,
      ignore_status: ost$status,
      local_status: ost$status;



    status.normal := TRUE;

    rap$locate_directory_record (processing_record.subproduct_info_pointers.attributes_p^.name,
          processing_record.subproduct_info_pointers.attributes_p^.licensed_product, directory_pointers,
          directory_record_p);

    IF directory_record_p = NIL THEN
      initialize_directory_record (processing_record.subproduct_info_pointers.attributes_p,
            directory_record_p, directory_pointers.sequence_p, new_directory_record_count, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
    IFEND;

    IF processing_record.task_set <> $rat$task_selections [rac$update_directory_task] THEN

      { The subproduct underwent task processing other than just guaranteeing a directory
      { record was present.

      IF (directory_record_p^.deferred_information.installation_identifier <> rac$not_installed) AND
            (rac$reconcile_file_cycles_task IN processing_record.task_set) THEN

        { The subproduct was previously deferred.

        IF processing_header_p^.installation_command <> rac$activate_product THEN

          { The deferred files are believed to have been shifted out of position.
          { The deferred files can no longer be used.
          { Display the current deferred information to the job log along with a
          { message that the deferred files have been shifted and are no longer
          { recognized as deferred.

          osp$set_status_abnormal ('RA', rae$deferred_subproduct_cleared, directory_record_p^.
                subproduct (1, clp$trimmed_string_size (directory_record_p^.subproduct)), local_status);
          osp$append_status_parameter (osc$status_parameter_delimiter,
                directory_record_p^.deferred_information.subproduct_level
                (1, clp$trimmed_string_size (directory_record_p^.deferred_information.subproduct_level)),
                local_status);
          osp$append_status_parameter (osc$status_parameter_delimiter, directory_record_p^.
                licensed_product (1, clp$trimmed_string_size (directory_record_p^.licensed_product)),
                local_status);
          osp$generate_log_message ($pmt$ascii_logset [pmc$job_log], local_status, ignore_status);
        IFEND;

        { Clear the deferred information record and decrement the deferred count.

        directory_record_p^.deferred_information.installation_identifier := rac$not_installed;
        directory_pointers.header_p^.deferred_count := directory_pointers.header_p^.deferred_count - 1;

      IFEND;


      IF rac$activate_files_task IN processing_record.task_set THEN

        { An immediate installation was attempted for this subproduct.

        IF last_task_status = rac$task_completed THEN

          { Set the active information record.

          set_installation_information (subproduct_index, date_installed, processing_header_p,
                processing_record.subproduct_info_pointers.attributes_p,
                directory_record_p^.active_information);

          IF processing_record.subproduct_info_pointers.attributes_p^.subproduct_type = rac$release THEN

            { Set the general directory record and corrective base information.

            set_directory_record (processing_record.subproduct_info_pointers.attributes_p,
                  processing_record.installation_catalog_p, processing_header_p^.installation_defaults.
                  system_catalog.size, directory_record_p);

            set_installation_information (subproduct_index, date_installed, processing_header_p,
                  processing_record.subproduct_info_pointers.attributes_p,
                  directory_record_p^.corrective_base_information);

          IFEND;
          directory_record_p^.subproduct_corrupted := FALSE;

        ELSEIF directory_record_p^.active_information.installation_identifier <> rac$not_installed THEN

          { Processing failed and there is potential for subproduct corruption.

          IF processing_record.subproduct_info_pointers.attributes_p^.installation_scheme =
                rac$version_based THEN

            IF (processing_record.subproduct_info_pointers.attributes_p^.installer_procedure.path_length <>
                  0) AND (last_task >= rac$execute_installer_proc_task) THEN

              { The processing failed during execution of the installer procedure.  It cannot
              { be known what the installer procedure did, therefore, the previous active
              { level of the subproduct is assumed to be corrupted and the directory
              { will be set to reflect this.  The installation identifier for the just
              { failed installation will also be registered.

              directory_record_p^.subproduct_corrupted := TRUE;
              directory_record_p^.active_information.installation_identifier :=
                    processing_header_p^.installation_identifier;

            IFEND;

          ELSE {installation_scheme is rac$cycle_based}

            IF last_task >= rac$activate_files_task THEN

              { The processing failed after at least some of the subproduct's files were
              { moved to the active cycle.  There is now a mixture of subproduct levels
              { sitting in the active cycle.  The previous active level of the
              { subproduct is assumed to be corrupted and the directory will be set to
              { reflect this.  The installation identifier for the just failed
              { installation will also be registered.

              directory_record_p^.subproduct_corrupted := TRUE;
              directory_record_p^.active_information.installation_identifier :=
                    processing_header_p^.installation_identifier;

            IFEND;

          IFEND;
        IFEND;

      ELSEIF rac$stage_files_task IN processing_record.task_set THEN

        { A deferred installation was attempted for this subproduct.

        IF last_task_status = rac$task_completed THEN

          { Set the deferred information record and increment deferred count.

          set_installation_information (subproduct_index, date_installed, processing_header_p,
                processing_record.subproduct_info_pointers.attributes_p,
                directory_record_p^.deferred_information);

          directory_pointers.header_p^.deferred_count := directory_pointers.header_p^.deferred_count + 1;

        ELSE {task failed}
          { Nothing needs to be rectified.  Any existing active level is still okay.
        IFEND;

      IFEND;
    IFEND;

  PROCEND update_directory_for_subproduct;

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

{ PURPOSE:
{   This procedure goes through the subproduct processing list and updates
{   the records for any subproduct that requires directory update.
{
{ DESIGN:
{   The rule of thumb in step processing is that the failure of one
{   subproduct will not jeopardize the remaining subproducts.  Each
{   subproduct is processed independently.  The update directory step
{   attempts to hold to that rule even though its not such a clean
{   separation in processing.
{
{ NOTES:
{

  PROCEDURE update_directory_records
    (VAR installation_control_record {input} : rat$installation_control_record;
     VAR directory_pointers {input, output} : rat$idb_directory_pointers;
     VAR subproducts_failed_processing: boolean;
     VAR status: ost$status);


    VAR
      date_installed: ost$date_time,
      ignore_status: ost$status,
      last_task: rat$tasks,
      last_task_status: rat$task_status,
      new_directory_record_count: rat$subproduct_count,
      processing_record: rat$subp_processing_record,
      subproduct_index: rat$subproduct_count,
      task_status: ost$status;


    status.normal := TRUE;
    new_directory_record_count := 0;

    pmp$get_compact_date_time (date_installed, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

  /main/
    FOR subproduct_index := 1 TO UPPERBOUND (installation_control_record.subproduct_processing_records_p^) DO
      processing_record := installation_control_record.subproduct_processing_records_p^ [subproduct_index];

      IF (installation_control_record.job_identifier = processing_record.job_identifier) AND
            (rac$update_directory_task IN processing_record.task_set) THEN

        { The last task and task status from earlier steps are captured to be used
        { in updating the directory.  The directory is updated regardless of the
        { last task status value.  Afterwards, if the earlier task status was
        { failed the task status is reset to failed preventing any subsequent
        { steps from executing.

        last_task := processing_record.task;
        last_task_status := processing_record.task_status;

        rap$record_subproduct_status (rac$update_directory_task, rac$task_started, subproduct_index,
              installation_control_record, ignore_status);

        update_directory_for_subproduct (subproduct_index, date_installed, last_task, last_task_status,
              installation_control_record.processing_header_p, processing_record, directory_pointers,
              new_directory_record_count, task_status);

        IF task_status.normal THEN
          rap$record_subproduct_status (rac$update_directory_task, rac$task_completed, subproduct_index,
                installation_control_record, ignore_status);
        ELSE
          osp$generate_log_message ($pmt$ascii_logset [pmc$job_log], task_status, ignore_status);
          rap$record_subproduct_status (rac$update_directory_task, rac$task_failed, subproduct_index,
                installation_control_record, ignore_status);
          subproducts_failed_processing := TRUE;
        IFEND;

        IF last_task_status = rac$task_failed THEN
          installation_control_record.subproduct_processing_records_p^ [subproduct_index].task_status :=
                rac$task_failed;
        IFEND;

      IFEND;
    FOREND /main/;

    IF new_directory_record_count > 0 THEN
      combine_directory_records (new_directory_record_count, directory_pointers, status);
    IFEND;

  PROCEND update_directory_records;

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

{ PURPOSE:
{   This procedure copies the updated directory into the IDB directory
{   file.
{
{ DESIGN:
{
{ NOTES:
{

  PROCEDURE write_idb_directory_file
    (    directory_fid: amt$file_identifier;
     VAR directory_segment_pointer {input} : amt$segment_pointer;
     VAR scratch_seq_p: ^SEQ ( * );
     VAR status: ost$status);


    VAR
      file_sequence_p: ^rat$idb_directory_sequence,
      memory_sequence_p: ^rat$idb_directory_sequence,
      sequence_length: integer;


    status.normal := TRUE;

    { Copy the directory from the scratch segment to the directory file.

    sequence_length := i#current_sequence_position (scratch_seq_p);

    RESET scratch_seq_p;
    NEXT memory_sequence_p: [[REP sequence_length OF cell]] IN scratch_seq_p;
    IF memory_sequence_p = NIL THEN
      osp$set_status_abnormal ('RA', rae$accessed_beyond_segment_eoi, 'IDB directory', status);
      osp$append_status_parameter (osc$status_parameter_delimiter, 'MEMORY SEQUENCE', status);
      RETURN;
    IFEND;

    RESET directory_segment_pointer.sequence_pointer;
    NEXT file_sequence_p: [[REP sequence_length OF cell]] IN directory_segment_pointer.sequence_pointer;
    IF file_sequence_p = NIL THEN
      osp$set_status_abnormal ('RA', rae$accessed_beyond_segment_eoi, 'IDB directory', status);
      osp$append_status_parameter (osc$status_parameter_delimiter, 'FILE SEQUENCE', status);
      RETURN;
    IFEND;

    file_sequence_p^ := memory_sequence_p^;

    amp$set_segment_eoi (directory_fid, directory_segment_pointer, status);

  PROCEND write_idb_directory_file;
MODEND ram$update_directory;
