?? NEWTITLE := '  NOS/VE Set Management ' ??
MODULE stm$modify_vst;
?? RIGHT := 110 ??

{ PURPOSE:
{   This module includes all procedure that modify the volume set  table.   In
{   general the volume set table must have been attached prior to calling most
{   of these routines.
{
{ DESIGN:
{   This module lives in the system core module 133.

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc ste$error_condition_codes
*copyc gft$system_file_identifier
*copyc ost$status
?? POP ??
*copyc osp$append_status_parameter
*copyc osp$reset_heap
*copyc osp$set_status_abnormal
*copyc stp$build_member_list_locator
*copyc stp$build_member_list_pointer
*copyc stp$build_pf_root_locator
*copyc stp$build_pf_root_pointer
*copyc stp$open_vst
*copyc stp$return_opened_vst
*copyc stp$search_ast_by_set
*copyc stp$search_mvl_for_vol
?? OLDTITLE ??
?? NEWTITLE := '  [XDCL, #GATE] stp$add_member_in_master_vst ', EJECT ??
*copyc sth$add_member_in_master_vst

  PROCEDURE [XDCL, #GATE] stp$add_member_in_master_vst
    (    p_master_vst: ^stt$vol_set_table;
         member_vol: rmt$recorded_vsn;
         member_internal_vsn: dmt$internal_vsn;
         dm_packet_storage: stt$dm_packet_storage;
     VAR status: ost$status);

    VAR
      mvl_index: stt$mvl_index,
      p_new_member_vsn_list: ^stt$member_vsn_list,
      unused_entry_found: boolean;

    stp$build_member_list_pointer (p_master_vst^.member_vsn_list_locator, p_master_vst,
          p_new_member_vsn_list);
    stp$search_mvl_for_unused_entry (p_new_member_vsn_list, mvl_index, unused_entry_found);
    IF unused_entry_found THEN
      {store information about the member in the master.
      status.normal := TRUE;
      p_new_member_vsn_list^ [mvl_index].entry_type := stc$valid;
      p_new_member_vsn_list^ [mvl_index].member_vsn := member_vol;
      p_new_member_vsn_list^ [mvl_index].member_internal_vsn := member_internal_vsn;
      p_new_member_vsn_list^ [mvl_index].member_dm_packet_storage := dm_packet_storage;
    ELSE
      {the member vsn list is of fixed size in the volume set table.
      osp$set_status_abnormal (stc$set_management_id, ste$exceeded_max_num_vol, p_master_vst^.set_name,
            status);
      osp$append_status_parameter (osc$status_parameter_delimiter, member_vol, status);
    IFEND;

  PROCEND stp$add_member_in_master_vst;
?? OLDTITLE ??
?? NEWTITLE := '  [XDCL, #GATE] stp$build_member_vst', EJECT ??
*copyc sth$build_member_vst

  PROCEDURE [XDCL, #GATE] stp$build_member_vst
    (    p_member_vst: ^stt$vol_set_table;
         member_vsn: rmt$recorded_vsn;
         member_internal_vsn: dmt$internal_vsn;
         set_name: stt$set_name;
         unique_set_name: stt$unique_set_name;
         master_vol: rmt$recorded_vsn;
         master_internal_vsn: dmt$internal_vsn);

    p_member_vst^.vsn := member_vsn;
    p_member_vst^.internal_vsn := member_internal_vsn;
    p_member_vst^.entry_type := stc$valid;
    p_member_vst^.set_name := set_name;
    p_member_vst^.unique_set_name := unique_set_name;
    p_member_vst^.vol_status_in_set := stc$member_vol;
    p_member_vst^.master_vsn := master_vol;
    p_member_vst^.master_internal_vsn := master_internal_vsn;

  PROCEND stp$build_member_vst;
?? OLDTITLE ??
?? NEWTITLE := '  [XDCL, #GATE] stp$clear_root_recreated', EJECT ??

  PROCEDURE [XDCL, #GATE] stp$clear_root_recreated
    (    set_name: stt$set_name;
     VAR status: ost$status);

    VAR
      ast_entry: stt$active_set_entry,
      ast_index: stt$ast_index,
      local_status: ost$status,
      master_vol: rmt$recorded_vsn,
      master_vst_segment_pointer: mmt$segment_pointer,
      masters_sfid: gft$system_file_identifier,
      p_master_vst: ^stt$vol_set_table,
      set_found_in_ast: boolean;

    stp$search_ast_by_set (set_name, ast_entry, ast_index, set_found_in_ast);
    IF set_found_in_ast THEN
      master_vol := ast_entry.master_vsn;
    ELSE
      osp$set_status_abnormal (stc$set_management_id, ste$set_not_active, set_name, status);
      RETURN; {----->
    IFEND;
    stp$open_vst (master_vol, TRUE, masters_sfid, master_vst_segment_pointer, status);
    IF status.normal THEN
      p_master_vst := master_vst_segment_pointer.cell_pointer;
      p_master_vst^.root_recreated := stc$root_not_recreated;
      stp$return_opened_vst (masters_sfid, master_vst_segment_pointer, local_status);
      IF status.normal AND NOT local_status.normal THEN
        status := local_status;
      IFEND;
    IFEND;

  PROCEND stp$clear_root_recreated;
?? OLDTITLE ??
?? NEWTITLE := '  [XDCL, #GATE] stp$fill_master_vst', EJECT ??
*copyc sth$fill_master_vst

  PROCEDURE [XDCL, #GATE] stp$fill_master_vst
    (    p_master_vst: ^stt$vol_set_table;
         master_vsn: rmt$recorded_vsn;
         master_internal_vsn: dmt$internal_vsn;
         set_name: stt$set_name;
         unique_set: stt$unique_set_name;
         set_owner: ost$user_identification;
         dm_packet_storage: stt$dm_packet_storage;
         root_recreated: boolean;
     VAR status: ost$status);

    VAR
      p_heap: ^ost$heap,
      p_member_vsn_list: ^stt$member_vsn_list;

?? NEWTITLE := 'p$initialize_mvl_to_unused', EJECT ??

    PROCEDURE p$initialize_mvl_to_unused
      (    p_member_vsn_list: ^stt$member_vsn_list);

{    PURPOSE:
{      This initializes the member vsn list, of the master volume set table,
{      to indicate that there are no member volumes in the set, yeti.

      VAR
        mvl_index: stt$mvl_index;

      FOR mvl_index := LOWERBOUND (p_member_vsn_list^) TO UPPERBOUND (p_member_vsn_list^) DO
        p_member_vsn_list^ [mvl_index].entry_type := stc$unused;
      FOREND;

    PROCEND p$initialize_mvl_to_unused;
?? OLDTITLE ??
?? EJECT ??
    status.normal := TRUE;
    p_master_vst^.vsn := master_vsn;
    p_master_vst^.internal_vsn := master_internal_vsn;
    p_master_vst^.entry_type := stc$valid;
    p_master_vst^.set_name := set_name;
    p_master_vst^.unique_set_name := unique_set;
    p_master_vst^.vol_status_in_set := stc$master_vol;
    p_master_vst^.set_owner := set_owner;
    p_master_vst^.pf_root_storage.pf_root_ever_stored := FALSE;
    p_master_vst^.master_dm_packet_storage := dm_packet_storage;

    IF root_recreated THEN
      p_master_vst^.root_recreated := stc$root_recreated;
    ELSE
      p_master_vst^.root_recreated := stc$root_not_recreated;
    IFEND;

    p_heap := ^p_master_vst^.vst_heap;
    osp$reset_heap (p_heap, 1000000, FALSE, 1); {reset does not work}
    ALLOCATE p_member_vsn_list: [1 .. stc$max_num_members_on_set] IN p_heap^;
    IF p_member_vsn_list = NIL THEN
      {I made a mistake in choosing either size of heap or maximum number of volumes allowed on the set.
      osp$set_status_abnormal (stc$set_management_id, ste$no_space_vst_heap, master_vsn, status);
    ELSE
      p$initialize_mvl_to_unused (p_member_vsn_list);
      stp$build_member_list_locator (p_member_vsn_list, p_master_vst, p_master_vst^.member_vsn_list_locator);
    IFEND;

  PROCEND stp$fill_master_vst;
?? OLDTITLE ??
?? NEWTITLE := '  [XDCL, #GATE] stp$purge_vst_pf_root', EJECT ??
*copyc sth$purge_vst_pf_root

  PROCEDURE [XDCL, #GATE] stp$purge_vst_pf_root
    (    master_vsn: rmt$recorded_vsn;
     VAR status: ost$status);

    VAR
      local_status: ost$status,
      p_master_vst: ^stt$vol_set_table,
      p_old_pf_root: ^pft$root,
      sfid: gft$system_file_identifier,
      vst_segment_pointer: mmt$segment_pointer;

    stp$open_vst (master_vsn, TRUE, sfid, vst_segment_pointer, status);

    IF status.normal THEN
      p_master_vst := vst_segment_pointer.cell_pointer;
      IF p_master_vst^.pf_root_storage.pf_root_ever_stored THEN
        stp$build_pf_root_pointer (p_master_vst^.pf_root_storage.pf_root_locator, p_master_vst,
              p_old_pf_root);
        IF p_old_pf_root <> NIL THEN
          FREE p_old_pf_root IN p_master_vst^.vst_heap;
        IFEND;
      IFEND;
      p_master_vst^.pf_root_storage.pf_root_ever_stored := FALSE;
      stp$return_opened_vst (sfid, vst_segment_pointer, local_status);
    IFEND;

  PROCEND stp$purge_vst_pf_root;
?? OLDTITLE ??
?? NEWTITLE := '  [XDCL, #GATE] stp$remove_member_from_master', EJECT ??
*copyc sth$remove_member_from_master

  PROCEDURE [XDCL, #GATE] stp$remove_member_from_master
    (    member_vol: rmt$recorded_vsn;
         p_master_vst: ^stt$vol_set_table;
     VAR status: ost$status);

    VAR
      member_volume_found: boolean,
      mvl_index: stt$mvl_index,
      p_new_member_vsn_list: ^stt$member_vsn_list;

    {take care of relative pointer.
    stp$build_member_list_pointer (p_master_vst^.member_vsn_list_locator, p_master_vst,
          p_new_member_vsn_list);

    stp$search_mvl_for_vol (member_vol, p_new_member_vsn_list, mvl_index, member_volume_found);
    IF member_volume_found THEN
      status.normal := TRUE;
      p_new_member_vsn_list^ [mvl_index].entry_type := stc$unused;
    ELSE
      osp$set_status_abnormal (stc$set_management_id, ste$member_not_in_master, member_vol, status);
      osp$append_status_parameter (osc$status_parameter_delimiter, p_master_vst^.set_name, status);
    IFEND;

  PROCEND stp$remove_member_from_master;
?? OLDTITLE ??
?? NEWTITLE := '  [XDCL, #GATE] stp$remove_set_from_vst', EJECT ??
*copyc sth$remove_set_from_vst

  PROCEDURE [XDCL, #GATE] stp$remove_set_from_vst
    (    p_vst: ^stt$vol_set_table;
     VAR status: ost$status);

    VAR
      new_p_member_vsn_list: ^stt$member_vsn_list;

{   Make sure the member vsn list has been freed.
    IF p_vst^.entry_type = stc$valid THEN
      IF p_vst^.vol_status_in_set = stc$master_vol THEN
        stp$build_member_list_pointer (p_vst^.member_vsn_list_locator, p_vst, new_p_member_vsn_list);
        IF new_p_member_vsn_list <> NIL THEN
          FREE new_p_member_vsn_list IN p_vst^.vst_heap;
        IFEND;
      IFEND;
    IFEND;

    p_vst^.entry_type := stc$unused;
    status.normal := TRUE;
  PROCEND stp$remove_set_from_vst;
?? OLDTITLE ??
?? NEWTITLE := '  [XDCL] stp$search_mvl_for_unused_entry', EJECT ??
*copyc sth$search_mvl_for_unused_entry

  PROCEDURE [XDCL] stp$search_mvl_for_unused_entry
    (    p_member_vsn_list: ^stt$member_vsn_list;
     VAR mvl_index: stt$mvl_index;
     VAR unused_entry_found: boolean);


    IF p_member_vsn_list = NIL THEN
      unused_entry_found := FALSE;
    ELSE
      unused_entry_found := FALSE;

    /search_mvl_for_unused/
      FOR mvl_index := LOWERBOUND (p_member_vsn_list^) TO UPPERBOUND (p_member_vsn_list^) DO
        IF p_member_vsn_list^ [mvl_index].entry_type = stc$unused THEN
          unused_entry_found := TRUE;
          EXIT /search_mvl_for_unused/; {----->
        IFEND;
      FOREND /search_mvl_for_unused/;
    IFEND;
  PROCEND stp$search_mvl_for_unused_entry;

?? OLDTITLE ??
?? NEWTITLE := '  [XDCL] stp$store_dm_packet_in_master', EJECT ??
*copyc sth$store_dm_packet_in_master

  PROCEDURE [XDCL] stp$store_dm_packet_in_master
    (    master_vsn: rmt$recorded_vsn;
         inactive_member: rmt$recorded_vsn;
         new_dm_packet_storage: stt$dm_packet_storage;
     VAR status: ost$status);

    VAR
      local_status: ost$status,
      masters_segment_pointer: mmt$segment_pointer,
      masters_sfid: gft$system_file_identifier,
      mvl_index: stt$mvl_index,
      new_p_member_vsn_list: ^stt$member_vsn_list,
      p_master_vst: ^stt$vol_set_table,
      volume_found: boolean;

    stp$open_vst (master_vsn, TRUE, masters_sfid, masters_segment_pointer, status);
    IF status.normal THEN
      p_master_vst := masters_segment_pointer.cell_pointer;
      stp$build_member_list_pointer (p_master_vst^.member_vsn_list_locator, p_master_vst,
            new_p_member_vsn_list);
      stp$search_mvl_for_vol (inactive_member, new_p_member_vsn_list, mvl_index, volume_found);
      IF volume_found THEN
        stp$store_dm_packet_in_mvl (new_p_member_vsn_list, mvl_index, new_dm_packet_storage);
      ELSE
        osp$set_status_abnormal (stc$set_management_id, ste$vol_not_found, inactive_member, status);
      IFEND;
      stp$return_opened_vst (masters_sfid, masters_segment_pointer, local_status);
    IFEND;

  PROCEND stp$store_dm_packet_in_master;
?? OLDTITLE ??
?? NEWTITLE := '  [XDCL] stp$store_dm_packet_in_mvl', EJECT ??
*copyc sth$store_dm_packet_in_mvl

  PROCEDURE [XDCL] stp$store_dm_packet_in_mvl
    (    p_member_vsn_list: ^stt$member_vsn_list;
         mvl_index: stt$mvl_index;
         dm_packet_storage: stt$dm_packet_storage);

    p_member_vsn_list^ [mvl_index].member_dm_packet_storage := dm_packet_storage;

  PROCEND stp$store_dm_packet_in_mvl;
?? OLDTITLE ??
?? NEWTITLE := '  [XDCL] stp$store_master_dm_packet', EJECT ??
*copyc sth$store_master_dm_packet

  PROCEDURE [XDCL] stp$store_master_dm_packet
    (    p_master_vst: ^stt$vol_set_table;
         dm_packet_storage: stt$dm_packet_storage);

    p_master_vst^.master_dm_packet_storage := dm_packet_storage;

  PROCEND stp$store_master_dm_packet;
?? OLDTITLE ??
?? NEWTITLE := '  [XDCL] stp$store_member_dm_packet', EJECT ??
*copyc sth$store_member_dm_packet

  PROCEDURE [XDCL] stp$store_member_dm_packet
    (    p_master_vst: ^stt$vol_set_table;
         inactive_member: rmt$recorded_vsn;
         dm_packet_storage: stt$dm_packet_storage;
     VAR status: ost$status);

    VAR
      mvl_index: stt$mvl_index,
      new_p_member_vsn_list: ^stt$member_vsn_list,
      volume_found: boolean;

    stp$build_member_list_pointer (p_master_vst^.member_vsn_list_locator, p_master_vst,
          new_p_member_vsn_list);
    status.normal := TRUE;
    stp$search_mvl_for_vol (inactive_member, new_p_member_vsn_list, mvl_index, volume_found);
    IF volume_found THEN
      stp$store_dm_packet_in_mvl (new_p_member_vsn_list, mvl_index, dm_packet_storage);
    ELSE
      osp$set_status_abnormal (stc$set_management_id, ste$vol_not_found, inactive_member, status);
    IFEND;

  PROCEND stp$store_member_dm_packet;
?? OLDTITLE ??
?? NEWTITLE := '  [XDCL, #GATE] stp$store_vst_pf_root', EJECT ??
*copyc sth$store_vst_pf_root

  PROCEDURE [XDCL, #GATE] stp$store_vst_pf_root
    (    master_vsn: rmt$recorded_vsn;
         pf_root: pft$root;
     VAR status: ost$status);

    VAR
      input_root_size: pft$root_size,
      local_status: ost$status,
      p_master_vst: ^stt$vol_set_table,
      p_new_pf_root: ^pft$root,
      p_old_pf_root: ^pft$root,
      sfid: gft$system_file_identifier,
      vst_segment_pointer: mmt$segment_pointer;

    input_root_size := #SIZE (pf_root);
    stp$open_vst (master_vsn, TRUE, sfid, vst_segment_pointer, status);
    IF status.normal THEN
      p_master_vst := vst_segment_pointer.cell_pointer;
      ALLOCATE p_new_pf_root: [[REP input_root_size OF cell]] IN p_master_vst^.vst_heap;
      IF p_new_pf_root = NIL THEN
        osp$set_status_abnormal (stc$set_management_id, ste$no_space_vst_heap, master_vsn, status);
      ELSE
        IF p_master_vst^.pf_root_storage.pf_root_ever_stored THEN
          stp$build_pf_root_pointer (p_master_vst^.pf_root_storage.pf_root_locator, p_master_vst,
                p_old_pf_root);
          IF p_old_pf_root <> NIL THEN
            FREE p_old_pf_root IN p_master_vst^.vst_heap;
          IFEND;
        IFEND;
        p_master_vst^.pf_root_storage.pf_root_ever_stored := TRUE;
        p_master_vst^.pf_root_storage.pf_root_size := input_root_size;
        p_new_pf_root^ := pf_root;
        stp$build_pf_root_locator (p_new_pf_root, p_master_vst,
              p_master_vst^.pf_root_storage.pf_root_locator);
      IFEND;
      stp$return_opened_vst (sfid, vst_segment_pointer, local_status);
    IFEND;

  PROCEND stp$store_vst_pf_root;
?? OLDTITLE ??
MODEND stm$modify_vst;
