/*static char *SCCSID = "@(#)format.c   6.8 91/11/06";*/
/***    FORMAT.C - Routines to handle the formatting.
 *
 *      Format
 *      Michael Walma
 *      Copyright March 1988, Microsoft Corp.
 *      March 28 1988
 *
 *      Modification History:
 *  @80714  14-Mar-1994 by F.Miro' - Fast Format
 *  @82508  20-Apr-1994 by F.Miro' - Re-Delta Fast Format
 *  @115263 03-Mar-1995 by Ch.Team - Added check to avoid overwrite on
 *                                   next partition.
 *
 *
 */

#define INCL_DOSDEVICES
#include "ldefs.h"
#include "ltypes.h"
#include "globals.h"
#include <pr_fmt.h>


/***    fmt_format_disk - format the Pinball partition
 *
 *      Through the use of helper routines fmt_format_disk initializes
 *      formatting data, prepares the disk for formatting, and formats
 *      it track by track, marking bad tracks bad as they are encountered.
 *
 *      fmt_format_disk ()
 *
 *      ENTRY           No parameters
 *
 *      EXIT            Returns NO_ERROR if successful, otherwise
 *                      error code.
 *
 *      CALLS           fmt_format_track
 *                      get_recomm_bpb
 *                      fmt_init_bad_block
 *                      fmt_init_bit_map
 *                      fmt_init_track_table
 *                      set_recomm_bpb
 *                      fmt_update_bit_maps
 *                      fmt_update_track_table
 *
 *      WARNINGS        May terminate program prematurely
 *
 *      EFFECTS         Destroys all data on the disk
 *                      Updates free and bad maps
 *                      Changes disk information
 *                      Allocates memory
 */
USHORT fmt_format_disk ()
{
    ULONG zero_data=0L;
    USHORT usTrashCan = 0;                /* BIGDISK */
    ULONG ulFSCtlPasswd = FSCP_PASSWD;    /* BIGDISK */
    USHORT rc;
    ULONG number_tracks_written;   //@80714
    UCHAR *scratchbuf;

#ifdef TRACE
    fprintf (stderr, "fmt_format_disk ()\n");
    fflush (stderr);
#endif

    /*
     * Issue the BeginFormat IOCTL to force HPFS to mount the volume.
     */

    if ( (rc = DosDevIOCtl ((char far *)"HPFS", (char far *)&zero_data,
                            IOCTL_BEGINFORMAT, IOCTL_CATEGORY,
                            disk_handle)) != NO_ERROR) {

            return (rc);
    }

//#101481 start
   /*
    * Allocate storage for boot and super block reads
    */
    scratchbuf = malloc (SECSIZE);
    if (scratchbuf == NULL) {
      com_dispmsg (rctomid (ERROR_NOT_ENOUGH_MEMORY), STDERR_CODE, NULL, 0);
      return (ERROR_NOT_ENOUGH_MEMORY);
    }

    // Read boot sector
    rc = read_scratch (0, (char far *)scratchbuf, 1);

    if (memcmp(scratchbuf+54, "HPFS    ", 8) == 0) {

    // It's an HPFS drive. Read super block
      rc = read_scratch ((ULONG)SEC_SUPERB, &sb, 1);

      if ( sb.sig1 == SBSIG1 && sb.sig2 == SBSIG2 &&
          sb.culNumBadSects > 50 )
        fmt_format_track_flag = TRUE; /* too many bad sectors; do slow format */

    } /* end new format code */

    free (scratchbuf);                  /* deallocate memory */

//#101481 end

    /*
     * Set up the bit maps and bad block lists.  Also initialize the
     * table used by the FORMAT TRACK routine.
     */

    fmt_init_bit_map ();
    fmt_init_bad_block ();

    fmt_init_track_table ();

//@80714
   if (fmt_format_track_flag) {
     do {
            if (!fmt_format_track ())           /* format a track if not /N */
              fmt_update_bit_maps ();           /* failed - mark as bad */

     } while (fmt_update_track_table ());       /* go to next track */

   } else {

  /* write to the start of the disk */
     number_tracks_written = fmt_tracks_start_volume;
    do {
      if ((number_tracks_written--) == 0)
        break;
           if (!fmt_format_track ())    /* format a track       */
             fmt_update_bit_maps ();            /* failed - mark as bad */
    } while (fmt_update_track_table ());        /* go to next track */

  /* skip to the start of the middle range of the disk */
     number_tracks_written =
      fmt_start_track_mid_volume - fmt_tracks_start_volume;
    do {
      if ((number_tracks_written--) == 0)
        break;
    } while (fmt_update_track_table ());        /* go to next track */

  /* write to the middle range of the disk for n tracks */
     number_tracks_written = fmt_number_mid_volume_tracks;
    if (fmt_tracks_left) /*115263*/
     do {
       if ((number_tracks_written--) == 0)
         break;
           if (!fmt_format_track ())            /* format a track    */
              fmt_update_bit_maps ();            /* failed - mark as bad */
     } while (fmt_update_track_table ());        /* go to next track */
   }

    /* now indicate that we are 100% done */
         if ( fmt_usepipe ) {

        usPipeMgr( PERCENT_DONE_MSG, NULL, 0, (USHORT)100, NULL, hfileFmtPipe, 0, NULL, 0 );
                                                                                                        // percent returned via msg parm

         } else {
                strcpy (scratchptr, "100");
                 FMT_COMPUTMSG( PERCENT_DONE_MSG, &scratchptr, 1, FMT_PERCENT_DONE_STR, msgfilename, STDOUT_CODE,
                      NO_RESPONSE, NULL, 0);
                 printf ("\r");
                 fflush (stdout);                       /* jump back to beginning of line */


#ifdef PMFRONTEND
       if (fmt_pmfrontend)                             //PCR PM FRONT END
       {                                               //PCR PM FRONT END
         printf ("\nMSG_%u\n", FMT_FORMAT_COMPL_STR);  //PCR PM FRONT END
         fflush (stdout);                              //PCR PM FRONT END
       }                                               //PCR PM FRONT END
#endif

                 computmsg( NULL, 0, FMT_FORMAT_COMPL_STR, msgfilename, STDOUT_CODE,
                      NO_RESPONSE, NULL, 0);

         }

    return (NO_ERROR);
}

/***    fmt_init_track_table - set up for formatting
 *
 *      The track table is a packet of information organized for the
 *      Format Track IOCTL.  This routine sets up the format packet to
 *      start formatting at the beginning of the Pinball partition.
 *
 *      This routine also displays the initial header for the cylinder-
 *      head display.
 *
 *      fmt_init_track_table (void)
 *
 *      ENTRY           No parameters
 *
 *      EXIT            No return value
 *
 *      CALLS           computmsg
 *
 *      WARNINGS        None
 *
 *      EFFECTS         Track table is initialized
 */
void fmt_init_track_table (void)
{
    USHORT i;
    ULONG temp_tracks;                               /* BIGDISK */
    ULONG mid_volume_track;                                  /* BIGDISK */

#ifdef TRACE
    fprintf (stderr, "Initializing track table\n");
    fflush (stderr);
#endif

    /*
     * Count the tracks on the disk.
     * This count is decremented as each track is formatted.
     */
    fmt_tracks_left = number_of_sectors / prm.spt;   /* BIGDISK */

//@80714
    /* Write 0xF6's to the beginning of the volume to cover the first two
     * tracks, the hot-fix area, and a percentage (.5%) of the middle
     * range of the volume.
     */
    if (fmt_format_track_flag == FALSE) {
       fmt_tracks_start_volume = fmt_tracks_left / 400L + 2L;
       mid_volume_track = fmt_tracks_left / 2L;
       fmt_start_track_mid_volume =
         mid_volume_track - (fmt_tracks_left / 400L) - 32L;
       fmt_number_mid_volume_tracks =
         mid_volume_track + (fmt_tracks_left / 400L) + 32L -
          fmt_start_track_mid_volume;
    }

    /*
     * The partition offset indicates sectors in partitions earlier on
     * the physical disk than the partition we're formatting.  We need
     * to calculate the beginning of the partition to avoid formatting
     * those other partitions.
     */

    if (partition_offset)
        temp_tracks = ((partition_offset - 1L) / (ULONG)prm.spt) + 1L;  /* BIGDISK */
    else
        temp_tracks = 0L;                                               /* BIGDISK */

    fmt_current_head = (USHORT) (temp_tracks % prm.nh);                 /* BIGDISK */
    fmt_current_cyl = (USHORT) (temp_tracks / prm.nh);                  /* BIGDISK */

    /*
     * Fill in the format packet
     */

    dp.head = fmt_current_head;
    dp.cyl = fmt_current_cyl;
    dp.sect = 0;
    dp.nsect = prm.spt;

    if (fmt_format_flag)
    {
       blank_buf = halloc ((ULONG)prm.spt, SECSIZE);        // PCR CP20 B721206 (from BJH CP13 B715023)
       pinboot.Extended_Boot.Boot_BPB = rec_param.dev_bpb;
//     memcpy (blank_buf, &pinboot, SECSIZE);                /* CP20 B719630 */
       //
       // CP20 B719630  - Don't write boot sector until format is complete!!!
       //                 This will prevent HPFS from trying to mount drive
       //                 on reboot if the format was interrupted
       //
       for (i=0; i<prm.spt; i++)                            // CP20 B719630 - PCR CP20 B721206 (from BJH CP13 B715023)
          memset (&blank_buf [i * SECSIZE], 0xf6, SECSIZE);
    }

    /*
     * Print the first formatting message
     */

    FMT_COMPUTMSG( SYSTEM_MSG, NULL, 0, FMT_FORMATTING_STR, msgfilename, STDOUT_CODE,
               NO_RESPONSE, NULL, 0);

         if ( fmt_usepipe ) {

        usPipeMgr( PERCENT_DONE_MSG, NULL, 0, (USHORT)0, NULL, hfileFmtPipe, 0, NULL, 0 );
                                                                                                        // percent returned via msg parm

         } else

        if (!stdout_redir
#ifdef PMFRONTEND
          || fmt_pmfrontend                                            //PCR PM FRONT END
#endif
      ) {
                        strcpy (scratchptr, "0");
#ifdef PMFRONTEND
         if (fmt_pmfrontend)                                           //PCR PM FRONT END
         {                                                             //PCR PM FRONT END
           printf ("\nMSG_%u,%s\n", FMT_PERCENT_DONE_STR, scratchptr); //PCR PM FRONT END
           fflush (stdout);                                            //PCR PM FRONT END
         }                                                             //PCR PM FRONT END
#endif
                        computmsg( &scratchptr, 1, FMT_PERCENT_DONE_STR, msgfilename,
                           STDOUT_CODE, NO_RESPONSE, NULL, 0);
                        printf ("\r");
                        fflush (stdout);
        }
}

/***    fmt_update_track_table - update format packet to next track
 *
 *      This function is called after a track has been successfully
 *      formatted.  It updates the head and cylinder numbers in the
 *      format packet to indicate the next track to be formatted.
 *      If the last track on the disk has been formatted, a zero
 *      value is returned.
 *
 *      fmt_update_track_table (void)
 *
 *      ENTRY           No parameters
 *
 *      EXIT            Returns FALSE if end of disk reached
 *
 *      CALLS           None
 *
 *      WARNINGS        None
 *
 *      EFFECTS         Track table modified
 */
USHORT fmt_update_track_table (void)
{
    ULONG  prev_track;                      /* BIGDISK */
    USHORT oldpcnt, newpcnt;

    if (fmt_format_flag) {
        /* erase the boot sector we installed */
        memset (blank_buf, 0xf6, SECSIZE);
    }

    prev_track = ((number_of_sectors / prm.spt) - fmt_tracks_left);  /* BIGDISK */

    if (!(--fmt_tracks_left))
        return (FALSE);

    /*
     * Move to the next head in this cylinder.
     */

    fmt_current_head = (fmt_current_head + 1) % prm.nh;

    /*
     * If we wrapped to the first head (head 0) again, move to
     * the next cylinder.
     */

    if (!fmt_current_head)
        fmt_current_cyl++;

    dp.head = fmt_current_head;
    dp.cyl = fmt_current_cyl;

    /*
     * Update the percent-done display.
     */

    if (fmt_format_flag &&
#ifdef PMFRONTEND
    (                                   //PCR PM FRONT END
#endif
    !stdout_redir
#ifdef PMFRONTEND
    || fmt_pmfrontend)                  //PCR PM FRONT END
#endif
    ) {
        oldpcnt = (USHORT)(((prev_track * prm.spt *                 /* BIGDISK */
                             100L / number_of_sectors) / PERCENT_RES) * PERCENT_RES);
        newpcnt = (USHORT)((((prev_track+1L) * prm.spt *
                             100L / number_of_sectors) / PERCENT_RES) * PERCENT_RES);
        if (newpcnt > oldpcnt) {
                if ( fmt_usepipe ) {

                usPipeMgr( PERCENT_DONE_MSG, NULL, 0, newpcnt, NULL, hfileFmtPipe, 0, NULL, 0 );
                                                                                                                // percent returned via msg parm
                } else {

                itoa (newpcnt, scratchptr, 10);
#ifdef PMFRONTEND
         if (fmt_pmfrontend)                                           //PCR PM FRONT END
         {                                                             //PCR PM FRONT END
           printf ("\nMSG_%u,%s\n", FMT_PERCENT_DONE_STR, scratchptr); //PCR PM FRONT END
           fflush (stdout);                                            //PCR PM FRONT END
         }                                                             //PCR PM FRONT END
#endif
                computmsg( &scratchptr, 1, FMT_PERCENT_DONE_STR, msgfilename,
                           STDOUT_CODE, NO_RESPONSE, NULL, 0);
                printf ("\r");
                fflush (stdout);        /* jump back to beginning of line */
           }
        }
    }

#ifdef TRACE
    fprintf (stderr, "head - %d cyl - %d\n", fmt_current_head, fmt_current_cyl);
    fflush (stderr);
#endif

    return (TRUE);
}

/***    fmt_update_bit_maps - mark bad tracks in bitmap and bad block list
 *
 *      This routine is called when fmt_format_track finds a bad track.
 *      Since the format IOCTL cannot distinguish individual sectors,
 *      we add the entire track's logical sectors to the bad block
 *      list, and mark those sectors as "in use" in the bitmap, so
 *      that the file system will avoid them.
 *
 *      The routine uses the fmt_tracks_left variable to determine which
 *      track was just formatted.
 *
 *      fmt_update_bit_maps (void)
 *
 *      ENTRY           No parameters
 *
 *      EXIT            No return value
 *
 *      CALLS           clr_bit
 *                      fmt_get_bad_list
 *
 *      WARNINGS        None
 *
 *      EFFECTS         Modifies free map and bad list
 *                      Bad sector count increased
 */
void fmt_update_bit_maps (void)
{
    ULONG lsn, maxlsn;

#ifdef TRACE
    fprintf (stderr, "updating bit maps\n");
    fflush (stderr);
#endif

    lsn = number_of_sectors -                                    /* BIGDISK */
          (unsigned long)(prm.spt * fmt_tracks_left);
    maxlsn = (lsn + prm.spt + 3) & ~3L; /* pad out to end of cache blk */
    lsn &= ~3L;                         /* start at beg. of cache blk */

#ifdef TRACE
    fprintf (stderr, "initial bit - %lu\n", lsn);
    fflush (stderr);
#endif

    for (; lsn < maxlsn; lsn++) {       /* for each sector in the trk */
        clr_bit (lsn);          /* mark as in use */

        /*
         * If we get to the end of the currently allocated bad block list,
         * we need to add a new block to the end.  In any case, we add
         * this sector to the primary and secondary bad block lists.
         */

        if (num_bad_sectors && !(num_bad_sectors % (SECSIZE-1))) {
            fmt_num_bad_blocks = (USHORT)(num_bad_sectors / (SECSIZE-1) + 1);
            fmt_bad  = fmt_get_bad_list (fmt_bad,  fmt_num_bad_blocks);
#ifdef TWO_MAPS
            fmt_bad2 = fmt_get_bad_list (fmt_bad2, fmt_num_bad_blocks);
#endif
        }
        fmt_bad [fmt_num_bad_blocks-1].list [num_bad_sectors % (SECSIZE-1)] =
#ifdef TWO_MAPS
            fmt_bad2 [fmt_num_bad_blocks-1].list [num_bad_sectors % (SECSIZE-1)] =
#endif
            lsn;
        num_bad_sectors++;
    }
}

void FMT_COMPUTMSG (                            //PCR PM FRONT END
  USHORT   msgtype,                             //PCR PM FRONT END
  CHAR     **ivtable,                           //PCR PM FRONT END
  USHORT   ivcount,                             //PCR PM FRONT END
  USHORT   message_number,                                       //PCR PM FRONT END
  CHAR     *message_file_name,                  //PCR PM FRONT END
  USHORT   device_type,                         //PCR PM FRONT END
  USHORT   responce_type,                       //PCR PM FRONT END
  CHAR     *key_buff,                                //PCR PM FRONT END
  USHORT   key_buff_len)                                                      //PCR PM FRONT END
{                                               //PCR PM FRONT END
  if ( fmt_usepipe )                            //PCR PM FRONT END
  {                                             //PCR PM FRONT END
   usPipeMgr(                                   //PCR PM FRONT END
     (USHORT ) msgtype,                         //PCR PM FRONT END
     (CHAR **) ivtable,                         //PCR PM FRONT END
     (USHORT ) ivcount,                         //PCR PM FRONT END
     (USHORT ) message_number,                  //PCR PM FRONT END
     (CHAR * ) message_file_name,               //PCR PM FRONT END
     (USHORT ) hfileFmtPipe,                    //PCR PM FRONT END
     (USHORT ) responce_type,                   //PCR PM FRONT END
     (CHAR * ) key_buff,                        //PCR PM FRONT END
     (USHORT ) key_buff_len);                   //PCR PM FRONT END
  }                                             //PCR PM FRONT END
  else                                          //PCR PM FRONT END
  {                                             //PCR PM FRONT END
#ifdef PMFRONTEND
    if (fmt_pmfrontend)                         //PCR PM FRONT END
    {                                           //PCR PM FRONT END
      unsigned iv_i;                            //PCR PM FRONT END
                                                //PCR PM FRONT END
      printf ("\nMSG_%u", message_number);      //PCR PM FRONT END
      if (ivcount != 0)                         //PCR PM FRONT END
      {                                         //PCR PM FRONT END
        for (iv_i = 0; iv_i < ivcount; iv_i++)  //PCR PM FRONT END
        {                                       //PCR PM FRONT END
          printf (",%s", * (ivtable + iv_i));   //PCR PM FRONT END
        }                                       //PCR PM FRONT END
      }                                         //PCR PM FRONT END
      printf ("\n");                            //PCR PM FRONT END
      fflush (stdout);                          //PCR PM FRONT END
    }                                           //PCR PM FRONT END
#endif
    computmsg(                                  //PCR PM FRONT END
      (char **)   ivtable,                      //PCR PM FRONT END
      (unsigned)  ivcount,                      //PCR PM FRONT END
      ( unsigned) message_number,               //PCR PM FRONT END
      (char *  )  message_file_name,            //PCR PM FRONT END
      (unsigned)  device_type,                  //PCR PM FRONT END
      (unsigned)  responce_type,                //PCR PM FRONT END
      (char * )   key_buff,                     //PCR PM FRONT END
      (unsigned)  key_buff_len);                //PCR PM FRONT END
  }                                             //PCR PM FRONT END
}                                               //PCR PM FRONT END
