?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE Device Management' ??
MODULE dmm$create_new_file;
?? RIGHT := 110 ??


?? NEWTITLE := 'Global Declarations Referenced By This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc amt$file_byte_address
*copyc dmt$allocation_size
*copyc dmt$chapter_number
*copyc dmt$error_condition_codes
*copyc dmt$file_attributes
*copyc dmt$file_location
*copyc dmt$file_share_history
*copyc dmt$global_file_name
*copyc dmt$new_device_file_attribute
*copyc dmt$new_file_attribute
*copyc gft$system_file_identifier
*copyc gft$table_residence
*copyc ost$status
*copyc ost$wait
*copyc pft$share_selections
*copyc pft$usage_selections
*copyc sft$file_space_limit_kind
?? POP ??
*copyc dmp$allocate_file_space_r1
*copyc dmp$clear_master_attach_lock
*copyc dmp$close_file
*copyc dmp$create_disk_file_descriptor
*copyc dmp$create_fd_entry
*copyc dmp$create_fmds
*copyc dmp$destroy_file
*copyc dmp$determine_queue_status
*copyc dmp$evacuate_active_device_log
*copyc dmp$generate_gfn_hash
*copyc dmp$get_active_vol_attributes
*copyc dmp$get_disk_file_descriptor_p
*copyc dmp$get_stored_fmd
*copyc dmp$open_directory
*copyc dmp$reserve_fmd
*copyc dmp$search_vol_directory_name
*copyc dmp$set_file_table_locator
*copyc dmp$set_ft_locator_residence
*copyc dmp$set_master_attach_lock
*copyc dmp$unconditional_get_dfd_p
*copyc gfp$get_locked_fde_p
*copyc gfp$lock_fde
*copyc gfp$unlock_fde_p
*copyc mmp$write_modified_pages
*copyc osp$generate_unique_binary_name
*copyc osp$set_status_abnormal
*copyc gfv$null_sfid
*copyc mmv$shared_pages_in_jws
*copyc osv$deadstart_phase
*copyc syv$job_initialization_complete

?? TITLE := '  dmp$create_device_file', EJECT ??

  PROCEDURE [XDCL, #GATE] dmp$create_device_file
    (    user_supplied_name: ost$name;
         recorded_vsn: rmt$recorded_vsn;
         p_file_attributes: ^array [1 .. * ] of dmt$new_device_file_attribute;
         byte_address: amt$file_byte_address;
     VAR system_file_id: gft$system_file_identifier;
     VAR status: ost$status);

    VAR
      p_file_descriptor_entry: ^gft$file_descriptor_entry,
      attributes: array [1 .. 3] of dmt$assigned_ms_vol_attribute,
      avt_index: dmt$active_volume_table_index,
      directory_sfid: gft$system_file_identifier,
      volume_active: boolean,
      logging_active: boolean,
      directory_index: dmt$directory_index,
      entry_found: boolean,
      global_file_name: dmt$global_file_name,
      local_status: ost$status;

    status.normal := TRUE;
    avt_index := 0;
    attributes [1].keyword := dmc$ms_volume_directory;
    attributes [2].keyword := dmc$avt_index;
    attributes [3].keyword := dmc$ms_device_log;

    dmp$get_active_vol_attributes (recorded_vsn, avt_index, attributes, volume_active);
    IF NOT volume_active THEN
{       issue mount request
      osp$set_status_abnormal (dmc$device_manager_ident, dme$avt_entry_not_found, 'dmp$create_device_file',
            status);
      RETURN; {----->
    IFEND;

    directory_sfid := attributes [1].directory_sfid;
    avt_index := attributes [2].index;
    logging_active := attributes [3].p_dlog <> gfv$null_sfid;

    directory_index := 0;
    dmp$search_vol_directory_name (user_supplied_name, directory_sfid, directory_index, entry_found, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    IF entry_found THEN
      osp$set_status_abnormal (dmc$device_manager_ident, dme$device_file_already_exists,
            'FILE ALREADY EXISTS', status);
      RETURN; {----->
    IFEND;

    create_volume_device_file (byte_address, p_file_attributes, recorded_vsn, system_file_id,
          global_file_name, status);

    IF status.normal THEN
      IF logging_active AND (osv$deadstart_phase <> osc$recovery_deadstart) THEN
        dmp$evacuate_active_device_log (avt_index, status);
      IFEND;

      IF status.normal THEN
        create_directory_entry (directory_sfid, user_supplied_name, global_file_name, system_file_id, status);
      IFEND;

      IF NOT status.normal THEN
        dmp$destroy_file (system_file_id, sfc$no_limit, local_status);
      IFEND;
    IFEND;

  PROCEND dmp$create_device_file;
?? TITLE := '  dmp$create_file_entry', EJECT ??
*copy dmh$create_file_entry

  PROCEDURE [XDCL, #GATE] dmp$create_file_entry
    (    file_kind: gft$file_kind;
         file_usage: pft$usage_selections;
         file_share_selections: pft$share_selections;
         file_share_history: dmt$file_share_history;
         p_file_attributes: ^array [ * ] of dmt$new_file_attribute;
         byte_address: amt$file_byte_address;
         assign_volume: boolean;
     VAR global_file_name: dmt$global_file_name;
     VAR system_file_id: gft$system_file_identifier;
     VAR status: ost$status);

    VAR
      able_to_reserve_fmd: boolean,
      allocate_byte_address: amt$file_byte_address,
      attachable_type_of_file: boolean,
      bytes_to_allocate: amt$file_byte_address,
      chapter_number: dmt$chapter_number,
      dfd_pointer: ost$relative_pointer,
      file_locator: dmt$file_location,
      fmd_index: dmt$fmd_index,
      file_space_limit: sft$file_space_limit_kind,
      index: integer,
      local_status: ost$status,
      lower: integer,
      p_dfd: ^dmt$disk_file_descriptor,
      p_file_descriptor_entry: ^gft$file_descriptor_entry,
      p_file_entry_attributes: ^array [ * ] of dmt$file_attribute,
      queue_status: gft$queue_status,
      upper: integer;

    VAR
      file_entry_attribute_p: ^dmt$file_attribute,
      file_attribute_p: ^dmt$new_file_attribute;

    file_space_limit := sfc$no_limit;
    chapter_number := 0;
    allocate_byte_address := 0;
    bytes_to_allocate := byte_address;

    osp$generate_unique_binary_name (global_file_name, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    dmp$set_ft_locator_residence (file_kind, system_file_id.residence, file_locator, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    IF (NOT syv$job_initialization_complete) AND (system_file_id.residence = gfc$tr_job) THEN
      {Local files created early must have same hash
      global_file_name.sequence_number := 0;
    IFEND;

    dmp$generate_gfn_hash (global_file_name, system_file_id.file_hash);

{determine the file's queue status
    dmp$determine_queue_status (file_kind, file_usage, file_share_selections, queue_status, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    attachable_type_of_file := (file_kind = gfc$fk_job_permanent_file) OR (file_kind = gfc$fk_device_file) OR
          (file_kind = gfc$fk_catalog);

    IF p_file_attributes = NIL THEN
      lower := 1;
      upper := 5;
      index := 0;
    ELSE
      lower := LOWERBOUND (p_file_attributes^);
      upper := UPPERBOUND (p_file_attributes^) + 6;
    IFEND;

    PUSH p_file_entry_attributes: [lower .. upper];

    IF p_file_attributes <> NIL THEN
      p_file_entry_attributes^ [upper].keyword := dmc$setname;
      p_file_entry_attributes^ [upper].setname := ' ';

      FOR index := LOWERBOUND (p_file_attributes^) TO UPPERBOUND (p_file_attributes^) DO
        file_attribute_p := ^p_file_attributes^ [index];
        file_entry_attribute_p := ^p_file_entry_attributes^ [index];
        IF (file_attribute_p^.keyword < LOWERVALUE (dmt$file_attribute_keywords))
{     } OR (file_attribute_p^.keyword > UPPERVALUE (dmt$file_attribute_keywords)) THEN
          osp$set_status_abnormal (dmc$device_manager_ident, dme$unrecognizable_case_select,
                'Bad case selector - dmp$create_file_entry.', status);
          RETURN; {----->
        IFEND;

        file_entry_attribute_p^.keyword := file_attribute_p^.keyword;
        CASE file_attribute_p^.keyword OF
        = dmc$class =
          file_entry_attribute_p^.class := file_attribute_p^.class;

        = dmc$class_ordinal =
          file_entry_attribute_p^.ordinal := file_attribute_p^.ordinal;

        = dmc$clear_space =
          file_entry_attribute_p^.required := file_attribute_p^.required;

        = dmc$file_limit =
          file_entry_attribute_p^.limit := file_attribute_p^.limit;

        = dmc$locked_file =
          file_entry_attribute_p^.file_lock := file_attribute_p^.file_lock;

        = dmc$master_volume_required =
          file_entry_attribute_p^.master_volume_required := file_attribute_p^.master_volume_required;

        = dmc$overflow =
          file_entry_attribute_p^.overflow_allowed := file_attribute_p^.overflow_allowed;

        = dmc$owner =
          file_entry_attribute_p^.file_space_limit := file_attribute_p^.file_space_limit;
          file_space_limit := file_attribute_p^.file_space_limit;

        = dmc$preset_value =
          file_entry_attribute_p^.preset_value := file_attribute_p^.preset_value;

        = dmc$requested_allocation_size =
          file_entry_attribute_p^.requested_allocation_size := file_attribute_p^.requested_allocation_size;

        = dmc$requested_transfer_size =
          file_entry_attribute_p^.requested_transfer_size := file_attribute_p^.requested_transfer_size;

        = dmc$requested_volume =
          file_entry_attribute_p^.requested_volume := file_attribute_p^.requested_volume;
          p_file_entry_attributes^ [upper].setname := file_attribute_p^.requested_volume.setname;

        = dmc$chapter_length =
          file_entry_attribute_p^.chapter_length := file_attribute_p^.chapter_length;
        ELSE
          ;
        CASEND;
      FOREND;
    IFEND;

    index := index + 1;
    p_file_entry_attributes^ [index].keyword := dmc$global_file_name;
    p_file_entry_attributes^ [index].global_file_name := global_file_name;
    index := index + 1;
    p_file_entry_attributes^ [index].keyword := dmc$file_kind;
    p_file_entry_attributes^ [index].file_kind := file_kind;
    index := index + 1;
    p_file_entry_attributes^ [index].keyword := dmc$file_hash;
    p_file_entry_attributes^ [index].file_hash := system_file_id.file_hash;
    index := index + 1;
    p_file_entry_attributes^ [index].keyword := dmc$write_mode;
    p_file_entry_attributes^ [index].attached_in_write_mode := attachable_type_of_file;
    index := index + 1;
    p_file_entry_attributes^ [index].keyword := dmc$queue_status;
    p_file_entry_attributes^ [index].queue_status := queue_status;

    IF attachable_type_of_file THEN
      dmp$set_master_attach_lock (system_file_id);
    IFEND;

    dmp$create_fd_entry (p_file_entry_attributes, system_file_id, status);

    IF attachable_type_of_file THEN
      dmp$clear_master_attach_lock (system_file_id);
    IFEND;
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    gfp$get_locked_fde_p (system_file_id, p_file_descriptor_entry);
    IF p_file_descriptor_entry = NIL THEN
      RETURN; {----->
    IFEND;

    dmp$get_disk_file_descriptor_p (p_file_descriptor_entry, p_dfd);

    dmp$create_fmds (file_locator, 1, p_dfd^);
    dmp$reserve_fmd (p_dfd, fmd_index, able_to_reserve_fmd);
    IF NOT able_to_reserve_fmd THEN
      osp$set_status_abnormal (dmc$device_manager_ident, dme$fmd_overflow, 'unable to reserve fmd entry',
            status);
      gfp$unlock_fde_p (p_file_descriptor_entry);
      RETURN; {----->
    IFEND;

    p_dfd^.current_fmd_index := fmd_index;

    gfp$unlock_fde_p (p_file_descriptor_entry);

    IF (assign_volume) OR (byte_address > 0) OR (file_kind = gfc$fk_device_file) THEN
      dmp$allocate_file_space_r1 (system_file_id, allocate_byte_address, bytes_to_allocate, chapter_number,
            osc$nowait, file_space_limit, status);
      IF NOT status.normal THEN
        dmp$destroy_file (system_file_id, file_space_limit, local_status);
        system_file_id := gfv$null_sfid;
      IFEND;
    IFEND;

  PROCEND dmp$create_file_entry;

?? TITLE := '  dmp$create_disk_file', EJECT ??

  PROCEDURE [XDCL] dmp$create_disk_file
    (    p_fde: gft$file_desc_entry_p;
         p_file_attributes: ^array [ * ] of dmt$file_attribute;
         allocation_length: amt$file_byte_address;
         system_file_id: gft$system_file_identifier;
     VAR status: ost$status);

    VAR
      able_to_reserve_fmd: boolean,
      allocate_byte_address: amt$file_byte_address,
      dfd_pointer: ost$relative_pointer,
      file_locator: dmt$file_location,
      fmd_index: dmt$fmd_index,
      index: integer,
      p_dfd: ^dmt$disk_file_descriptor,
      p_file_entry_attributes: ^array [ * ] of dmt$file_attribute;

    dmp$set_file_table_locator (system_file_id.residence, file_locator, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    gfp$lock_fde (p_fde);

    dmp$create_disk_file_descriptor (p_fde^.file_kind, file_locator, p_file_attributes, dfd_pointer);

    p_fde^.disk_file_descriptor_p := dfd_pointer;

    dmp$unconditional_get_dfd_p (p_fde, p_dfd);
    dmp$create_fmds (file_locator, 1, p_dfd^);
    dmp$reserve_fmd (p_dfd, fmd_index, able_to_reserve_fmd);
    IF NOT able_to_reserve_fmd THEN
      osp$set_status_abnormal (dmc$device_manager_ident, dme$fmd_overflow,
            'unable to reserve fmd entry - dmp$create_disk_file', status);
      gfp$unlock_fde_p (p_fde);
      RETURN; {----->
    IFEND;
    p_dfd^.current_fmd_index := fmd_index;
    p_fde^.media := gfc$fm_mass_storage_file;

    gfp$unlock_fde_p (p_fde);

  PROCEND dmp$create_disk_file;

?? TITLE := '  create_directory_entry', EJECT ??

  PROCEDURE create_directory_entry
    (    directory_sfid: gft$system_file_identifier;
         user_supplied_name: ost$name;
         global_file_name: dmt$global_file_name;
         system_file_id: gft$system_file_identifier;
     VAR status: ost$status);

    VAR
      p_directory: ^dmt$ms_volume_directory,
      available_directory_index: dmt$directory_index,
      directory_index: dmt$directory_index;

    dmp$open_directory (directory_sfid, osc$os_ring_1, osc$tsrv_ring, mmc$sar_write_extend, mmc$as_sequential,
          p_directory, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

  /create_entry/
    BEGIN

      available_directory_index := 0;

    /find_available_entry/
      FOR directory_index := 1 TO p_directory^.header.number_of_entries DO
        IF p_directory^.entries [directory_index].entry_available THEN
          available_directory_index := directory_index;
          EXIT /find_available_entry/; {----->
        IFEND;
      FOREND /find_available_entry/;

      IF available_directory_index = 0 THEN
        osp$set_status_abnormal (dmc$device_manager_ident, dme$directory_full, '', status);
        EXIT /create_entry/; {----->
      IFEND;

      p_directory^.entries [available_directory_index].user_supplied_name := user_supplied_name;
      p_directory^.entries [available_directory_index].global_file_name := global_file_name;

      dmp$get_stored_fmd (system_file_id, p_directory^.entries [available_directory_index].stored_df_fmd,
            status);
      IF status.normal THEN
        p_directory^.entries [directory_index].entry_available := FALSE;
        mmp$write_modified_pages (p_directory, #SIZE (p_directory^), osc$wait, status);
      IFEND;

    END /create_entry/;

    dmp$close_file (p_directory, status);

  PROCEND create_directory_entry;
?? TITLE := '  create_volume_device_file', EJECT ??

  PROCEDURE create_volume_device_file
    (    byte_address: amt$file_byte_address;
         p_file_attributes: ^array [1 .. * ] of dmt$new_device_file_attribute;
         recorded_vsn: rmt$recorded_vsn;
     VAR system_file_id: gft$system_file_identifier;
     VAR global_file_name: dmt$global_file_name;
     VAR status: ost$status);

    CONST
      assign_volume = TRUE;

    VAR
      file_usage: pft$usage_selections,
      file_share_selections: pft$share_selections,
      file_share_history: dmt$file_share_history,
      limit: amt$file_limit,
      requested_volume: dmt$requested_volume,
      local_file_attributes: ^array [1 .. * ] of dmt$new_file_attribute,
      attribute_index: integer;

    file_usage := $pft$usage_selections [pfc$read];
    file_share_selections := $pft$share_selections [];
    file_share_history := dmc$minimum_file_share_his;
    limit := byte_address;
    requested_volume.recorded_vsn := recorded_vsn;
    requested_volume.setname := ' ';

    PUSH local_file_attributes: [1 .. UPPERBOUND (p_file_attributes^) + 2];

    attribute_index := 0;

    IF p_file_attributes <> NIL THEN
      FOR attribute_index := 1 TO UPPERBOUND (p_file_attributes^) DO
        local_file_attributes^ [attribute_index].keyword := p_file_attributes^ [attribute_index].keyword;
        CASE p_file_attributes^ [attribute_index].keyword OF
        = dmc$clear_space =
          local_file_attributes^ [attribute_index].required := p_file_attributes^ [attribute_index].required;
        = dmc$file_limit =
          local_file_attributes^ [attribute_index].limit := p_file_attributes^ [attribute_index].limit;
          limit := p_file_attributes^ [attribute_index].limit;
        = dmc$preset_value =
          local_file_attributes^ [attribute_index].preset_value :=
                p_file_attributes^ [attribute_index].preset_value;
        = dmc$requested_allocation_size =
          local_file_attributes^ [attribute_index].requested_allocation_size :=
                p_file_attributes^ [attribute_index].requested_allocation_size;
        = dmc$requested_transfer_size =
          local_file_attributes^ [attribute_index].requested_transfer_size :=
                p_file_attributes^ [attribute_index].requested_transfer_size;
        CASEND;
      FOREND;
    IFEND;

    local_file_attributes^ [attribute_index + 1].keyword := dmc$requested_volume;
    local_file_attributes^ [attribute_index + 1].requested_volume := requested_volume;
    local_file_attributes^ [attribute_index + 2].keyword := dmc$file_limit;
    local_file_attributes^ [attribute_index + 2].limit := limit;

    dmp$create_file_entry (gfc$fk_device_file, file_usage, file_share_selections, file_share_history,
          local_file_attributes, byte_address, assign_volume, global_file_name, system_file_id, status);

  PROCEND create_volume_device_file;
MODEND dmm$create_new_file;
