/* Title:   MakeDrive.c.create
 *
 *          Creates DOS disk files
 *          01-06-92
 *          1998.12.01 W Warnings fettled and problems with boot sector fixed
 *          1998.12.10 W changes filetype before deleting to defeat GuardDD
 *          1999.01.26 W Above fix stops new paritions being created, so now checks 
                         file existence before trying to changetype/delete
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "kernel.h"
#include "swis.h"

#include "create.h"
#include "frontend.h"

/* CREATE PARTITION ROUTINES ******************************************** */

#define SECT_SIZE 512
#define BUF_SECTS 32             
                            
/* Partition types */

#define DOS33_SMALL     0x01
#define DOS33_BIG       0x04
#define DOS5            0x06

#define NFATs           2
#define ROOT_DIR_SECTS  32          
  /* Enough for 512 entries of 32 bytes each */

#define MSB(x) ( (x) >> 8 )
#define LSB(x) ( (x) & 0xFF )
  
struct DiskAddress
 { int head;
   int sect;
   int cyl;
 };


/* Disk parameters *************** */

static int    nsects, nheads, ntracks;
static int    part_type;

static int    disk_size;
static int    cluster_size;                      
static int    part_start;     /* Start of DOS partition */ 
static int    part_size;      /* Size of DOS partition */
static int    FAT_size;
static int    vol_serialno;

static struct DiskAddress Part_Start, Part_End;

static FILE  *outfile;

static char   buf[SECT_SIZE * BUF_SECTS];
         
/* Default sectors ***************************************** */

static char DOS3BootSector [SECT_SIZE] =

{
  0xEB, 0x3C, 0x90,                            /* 8086 jump */
  'M', 'S', 'D', 'O', 'S', '3', '.', '3',      /* OS ident */

  0x00, 0x02,                                  /* Sector size=200h*/
  0x08,                                        /* 8 sectors per cluster */
  0x01, 0x00,                                  /* Reserved sectors */

  NFATs,                                       /* Number of FATs */
  0x00, 0x02,                                  /* Root dir = 512 entries */
  0x00, 0x00,                                  /* Size of partition */ 
  0xF8,                                        /* Media ID */
  0x00, 0x00,                                  /* Size of each FAT */

  0x11, 0x00,                                  /* Sectors per track */
  0x04, 0x00,                                  /* No. of heads */
  0x11, 0x00,                                  /* No. of 'hidden' sectors */

                                      0x00, 0x00, /* Loader */
  0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0xE2, 
  0x13, 0x31, 0x22, 0x44, 0x4F, 0x53, 0x5F, 0x44, 
  0x52, 0x49, 0x56, 0x45, 0x20, 0x20, 0x46, 0x41, 
  0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0xFA, 0x33, 
  0xC0, 0x8E, 0xD0, 0xBC, 0x00, 0x7C, 0x16, 0x07, 
  0xBB, 0x78, 0x00, 0x36, 0xC5, 0x37, 0x1E, 0x56, 
  0x16, 0x53, 0xBF, 0x3E, 0x7C, 0xB9, 0x0B, 0x00, 
  0xFC, 0xF3, 0xA4, 0x06, 0x1F, 0xC6, 0x45, 0xFE, 
  0x0F, 0x8B, 0x0E, 0x18, 0x7C, 0x88, 0x4D, 0xF9, 
  0x89, 0x47, 0x02, 0xC7, 0x07, 0x3E, 0x7C, 0xFB, 
  0xCD, 0x13, 0x72, 0x79, 0x33, 0xC0, 0x39, 0x06, 
  0x13, 0x7C, 0x74, 0x08, 0x8B, 0x0E, 0x13, 0x7C, 
  0x89, 0x0E, 0x20, 0x7C, 0xA0, 0x10, 0x7C, 0xF7, 
  0x26, 0x16, 0x7C, 0x03, 0x06, 0x1C, 0x7C, 0x13, 
  0x16, 0x1E, 0x7C, 0x03, 0x06, 0x0E, 0x7C, 0x83, 
  0xD2, 0x00, 0xA3, 0x50, 0x7C, 0x89, 0x16, 0x52, 
  0x7C, 0xA3, 0x49, 0x7C, 0x89, 0x16, 0x4B, 0x7C, 
  0xB8, 0x20, 0x00, 0xF7, 0x26, 0x11, 0x7C, 0x8B, 
  0x1E, 0x0B, 0x7C, 0x03, 0xC3, 0x48, 0xF7, 0xF3, 
  0x01, 0x06, 0x49, 0x7C, 0x83, 0x16, 0x4B, 0x7C, 
  0x00, 0xBB, 0x00, 0x05, 0x8B, 0x16, 0x52, 0x7C, 
  0xA1, 0x50, 0x7C, 0xE8, 0x92, 0x00, 0x72, 0x1D, 
  0xB0, 0x01, 0xE8, 0xAC, 0x00, 0x72, 0x16, 0x8B, 
  0xFB, 0xB9, 0x0B, 0x00, 0xBE, 0xE6, 0x7D, 0xF3, 
  0xA6, 0x75, 0x0A, 0x8D, 0x7F, 0x20, 0xB9, 0x0B, 
  0x00, 0xF3, 0xA6, 0x74, 0x18, 0xBE, 0x9E, 0x7D, 
  0xE8, 0x5F, 0x00, 0x33, 0xC0, 0xCD, 0x16, 0x5E, 
  0x1F, 0x8F, 0x04, 0x8F, 0x44, 0x02, 0xCD, 0x19, 
  0x58, 0x58, 0x58, 0xEB, 0xE8, 0x8B, 0x47, 0x1A, 
  0x48, 0x48, 0x8A, 0x1E, 0x0D, 0x7C, 0x32, 0xFF, 
  0xF7, 0xE3, 0x03, 0x06, 0x49, 0x7C, 0x13, 0x16, 
  0x4B, 0x7C, 0xBB, 0x00, 0x07, 0xB9, 0x03, 0x00, 
  0x50, 0x52, 0x51, 0xE8, 0x3A, 0x00, 0x72, 0xD8, 
  0xB0, 0x01, 0xE8, 0x54, 0x00, 0x59, 0x5A, 0x58, 
  0x72, 0xBB, 0x05, 0x01, 0x00, 0x83, 0xD2, 0x00, 
  0x03, 0x1E, 0x0B, 0x7C, 0xE2, 0xE2, 0x8A, 0x2E, 
  0x15, 0x7C, 0x8A, 0x16, 0x24, 0x7C, 0x8B, 0x1E, 
  0x49, 0x7C, 0xA1, 0x4B, 0x7C, 0xEA, 0x00, 0x00, 
  0x70, 0x00, 0xAC, 0x0A, 0xC0, 0x74, 0x29, 0xB4, 
  0x0E, 0xBB, 0x07, 0x00, 0xCD, 0x10, 0xEB, 0xF2, 
  0x3B, 0x16, 0x18, 0x7C, 0x73, 0x19, 0xF7, 0x36, 
  0x18, 0x7C, 0xFE, 0xC2, 0x88, 0x16, 0x4F, 0x7C, 
  0x33, 0xD2, 0xF7, 0x36, 0x1A, 0x7C, 0x88, 0x16, 
  0x25, 0x7C, 0xA3, 0x4D, 0x7C, 0xF8, 0xC3, 0xF9, 
  0xC3, 0xB4, 0x02, 0x8B, 0x16, 0x4D, 0x7C, 0xB1, 
  0x06, 0xD2, 0xE6, 0x0A, 0x36, 0x4F, 0x7C, 0x8B, 
  0xCA, 0x86, 0xE9, 0x8A, 0x16, 0x24, 0x7C, 0x8A, 
  0x36, 0x25, 0x7C, 0xCD, 0x13, 0xC3, 0x0D, 0x0A, 
  0x4E, 0x6F, 0x6E, 0x2D, 0x53, 0x79, 0x73, 0x74, 
  0x65, 0x6D, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x20, 
  0x6F, 0x72, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x20, 
  0x65, 0x72, 0x72, 0x6F, 0x72, 0x0D, 0x0A, 0x52, 
  0x65, 0x70, 0x6C, 0x61, 0x63, 0x65, 0x20, 0x61, 
  0x6E, 0x64, 0x20, 0x70, 0x72, 0x65, 0x73, 0x73, 
  0x20, 0x61, 0x6E, 0x79, 0x20, 0x6B, 0x65, 0x79, 
  0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, 0x72, 0x65, 
  0x61, 0x64, 0x79, 0x0D, 0x0A, 0x00, 0x49, 0x4F, 
  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x59, 
  0x53, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x20, 0x20, 
  0x20, 0x53, 0x59, 0x53, 0x00, 0x00, 0x55, 0xAA 

};


static char DOS5BootSector [SECT_SIZE] =
{
  0xEB, 0x3C, 0x90,                              /* 8086 Jump */
  'M', 'S', 'D', 'O', 'S', '5', '.', '0',        /* OS ident  */
  0x00, 0x02,                                    /* Bytes per sector */
  0x04,                                          /* Cluster size */
  0x01, 0x00,                                    /* Reserved sectors */
  NFATs,                                         /* No. of FATs */
  0x00, 0x02,                                    /* Root dir. entries */
  0x00, 0x00,                                    /* Total sectors; 0=big */ 
  0xF8,                                          /* Media ID */
  0x00, 0x00,                                    /* FAT size */
  0x23, 0x00,                                    /* Sects per track */
  0x0C, 0x00,                                    /* No of heads */
  0x00, 0x00, 0x00, 0x00,                        /* Partition start.L */
  0x00, 0x00, 0x00, 0x00,                        /* Partition size.L */

  0x80,                                          /* Phys drive. no */
  0x00, 0x29,                                    /* Boot record signature */
  0x78, 0x56, 0x34, 0x12,                        /* Volume serial no. */

  'N','O',' ','N','A','M','E',' ',' ',' ',' ',   /* Volume label */

  'F','A','T','1','6',' ',' ',' ',               /* File sys type */       
               

                                      0xFA, 0x33,  /* Loader routine */
  0xC0, 0x8E, 0xD0, 0xBC, 0x00, 0x7C, 0x16, 0x07, 
  0xBB, 0x78, 0x00, 0x36, 0xC5, 0x37, 0x1E, 0x56, 
  0x16, 0x53, 0xBF, 0x3E, 0x7C, 0xB9, 0x0B, 0x00, 
  0xFC, 0xF3, 0xA4, 0x06, 0x1F, 0xC6, 0x45, 0xFE, 
  0x0F, 0x8B, 0x0E, 0x18, 0x7C, 0x88, 0x4D, 0xF9, 
  0x89, 0x47, 0x02, 0xC7, 0x07, 0x3E, 0x7C, 0xFB, 
  0xCD, 0x13, 0x72, 0x79, 0x33, 0xC0, 0x39, 0x06, 
  0x13, 0x7C, 0x74, 0x08, 0x8B, 0x0E, 0x13, 0x7C, 
  0x89, 0x0E, 0x20, 0x7C, 0xA0, 0x10, 0x7C, 0xF7, 
  0x26, 0x16, 0x7C, 0x03, 0x06, 0x1C, 0x7C, 0x13, 
  0x16, 0x1E, 0x7C, 0x03, 0x06, 0x0E, 0x7C, 0x83, 
  0xD2, 0x00, 0xA3, 0x50, 0x7C, 0x89, 0x16, 0x52, 
  0x7C, 0xA3, 0x49, 0x7C, 0x89, 0x16, 0x4B, 0x7C, 
  0xB8, 0x20, 0x00, 0xF7, 0x26, 0x11, 0x7C, 0x8B, 
  0x1E, 0x0B, 0x7C, 0x03, 0xC3, 0x48, 0xF7, 0xF3, 
  0x01, 0x06, 0x49, 0x7C, 0x83, 0x16, 0x4B, 0x7C, 
  0x00, 0xBB, 0x00, 0x05, 0x8B, 0x16, 0x52, 0x7C, 
  0xA1, 0x50, 0x7C, 0xE8, 0x92, 0x00, 0x72, 0x1D, 
  0xB0, 0x01, 0xE8, 0xAC, 0x00, 0x72, 0x16, 0x8B, 
  0xFB, 0xB9, 0x0B, 0x00, 0xBE, 0xE6, 0x7D, 0xF3, 
  0xA6, 0x75, 0x0A, 0x8D, 0x7F, 0x20, 0xB9, 0x0B, 
  0x00, 0xF3, 0xA6, 0x74, 0x18, 0xBE, 0x9E, 0x7D, 
  0xE8, 0x5F, 0x00, 0x33, 0xC0, 0xCD, 0x16, 0x5E, 
  0x1F, 0x8F, 0x04, 0x8F, 0x44, 0x02, 0xCD, 0x19, 
  0x58, 0x58, 0x58, 0xEB, 0xE8, 0x8B, 0x47, 0x1A, 
  0x48, 0x48, 0x8A, 0x1E, 0x0D, 0x7C, 0x32, 0xFF, 
  0xF7, 0xE3, 0x03, 0x06, 0x49, 0x7C, 0x13, 0x16, 
  0x4B, 0x7C, 0xBB, 0x00, 0x07, 0xB9, 0x03, 0x00, 
  0x50, 0x52, 0x51, 0xE8, 0x3A, 0x00, 0x72, 0xD8, 
  0xB0, 0x01, 0xE8, 0x54, 0x00, 0x59, 0x5A, 0x58, 
  0x72, 0xBB, 0x05, 0x01, 0x00, 0x83, 0xD2, 0x00, 
  0x03, 0x1E, 0x0B, 0x7C, 0xE2, 0xE2, 0x8A, 0x2E, 
  0x15, 0x7C, 0x8A, 0x16, 0x24, 0x7C, 0x8B, 0x1E, 
  0x49, 0x7C, 0xA1, 0x4B, 0x7C, 0xEA, 0x00, 0x00, 
  0x70, 0x00, 0xAC, 0x0A, 0xC0, 0x74, 0x29, 0xB4, 
  0x0E, 0xBB, 0x07, 0x00, 0xCD, 0x10, 0xEB, 0xF2, 
  0x3B, 0x16, 0x18, 0x7C, 0x73, 0x19, 0xF7, 0x36, 
  0x18, 0x7C, 0xFE, 0xC2, 0x88, 0x16, 0x4F, 0x7C, 
  0x33, 0xD2, 0xF7, 0x36, 0x1A, 0x7C, 0x88, 0x16, 
  0x25, 0x7C, 0xA3, 0x4D, 0x7C, 0xF8, 0xC3, 0xF9, 
  0xC3, 0xB4, 0x02, 0x8B, 0x16, 0x4D, 0x7C, 0xB1, 
  0x06, 0xD2, 0xE6, 0x0A, 0x36, 0x4F, 0x7C, 0x8B, 
  0xCA, 0x86, 0xE9, 0x8A, 0x16, 0x24, 0x7C, 0x8A, 
  0x36, 0x25, 0x7C, 0xCD, 0x13, 0xC3, 0x0D, 0x0A, 
  0x4E, 0x6F, 0x6E, 0x2D, 0x53, 0x79, 0x73, 0x74, 
  0x65, 0x6D, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x20, 
  0x6F, 0x72, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x20, 
  0x65, 0x72, 0x72, 0x6F, 0x72, 0x0D, 0x0A, 0x52, 
  0x65, 0x70, 0x6C, 0x61, 0x63, 0x65, 0x20, 0x61, 
  0x6E, 0x64, 0x20, 0x70, 0x72, 0x65, 0x73, 0x73, 
  0x20, 0x61, 0x6E, 0x79, 0x20, 0x6B, 0x65, 0x79, 
  0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, 0x72, 0x65, 
  0x61, 0x64, 0x79, 0x0D, 0x0A, 0x00, 0x49, 0x4F, 
  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x59, 
  0x53, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x20, 0x20, 
  0x20, 0x53, 0x59, 0x53, 0x00, 0x00, 0x55, 0xAA 
}; 

static char DefaultPartitionTable[SECT_SIZE] = 
{
 0xFA, 0x33, 0xC0, 0x8E, 0xD0, 0xBC, 0x00, 0x7C,    /* Loader routine */
 0x8B, 0xF4, 0x50, 0x07, 0x50, 0x1F, 0xFB, 0xFC, 
 0xBF, 0x00, 0x06, 0xB9, 0x00, 0x01, 0xF2, 0xA5,
 0xEA, 0x1D, 0x06, 0x00, 0x00, 0xBE, 0xBE, 0x07, 
 0xB3, 0x04, 0x80, 0x3C, 0x80, 0x74, 0x0E, 0x80,
 0x3C, 0x00, 0x75, 0x1C, 0x83, 0xC6, 0x10, 0xFE, 
 0xCB, 0x75, 0xEF, 0xCD, 0x18, 0x8B, 0x14, 0x8B,
 0x4C, 0x02, 0x8B, 0xEE, 0x83, 0xC6, 0x10, 0xFE, 
 0xCB, 0x74, 0x1A, 0x80, 0x3C, 0x00, 0x74, 0xF4,
 0xBE, 0x8B, 0x06, 0xAC, 0x3C, 0x00, 0x74, 0x0B, 
 0x56, 0xBB, 0x07, 0x00, 0xB4, 0x0E, 0xCD, 0x10,
 0x5E, 0xEB, 0xF0, 0xEB, 0xFE, 0xBF, 0x05, 0x00, 
 0xBB, 0x00, 0x7C, 0xB8, 0x01, 0x02, 0x57, 0xCD,
 0x13, 0x5F, 0x73, 0x0C, 0x33, 0xC0, 0xCD, 0x13, 
 0x4F, 0x75, 0xED, 0xBE, 0xA3, 0x06, 0xEB, 0xD3,
 0xBE, 0xC2, 0x06, 0xBF, 0xFE, 0x7D, 0x81, 0x3D, 
 0x55, 0xAA, 0x75, 0xC7, 0x8B, 0xF5, 0xEA, 0x00,
 0x7C, 0x00, 0x00, 0x49, 0x6E, 0x76, 0x61, 0x6C, 
 0x69, 0x64, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69,
 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x74, 0x61, 0x62, 
 0x6C, 0x65, 0x00, 0x45, 0x72, 0x72, 0x6F, 0x72,
 0x20, 0x6C, 0x6F, 0x61, 0x64, 0x69, 0x6E, 0x67, 
 0x20, 0x6F, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,
 0x6E, 0x67, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 
 0x6D, 0x00, 0x4D, 0x69, 0x73, 0x73, 0x69, 0x6E,
 0x67, 0x20, 0x6F, 0x70, 0x65, 0x72, 0x61, 0x74, 
 0x69, 0x6E, 0x67, 0x20, 0x73, 0x79, 0x73, 0x74,
 0x65, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 

 0x80,                 /* Boot indicator - 80h = bootable partition */
 0x01,                 /* Starting head */
 0x01,                 /* Starting sector */
 0x00,                 /* Starting cylinder */

 0x01,                 /* System: MS-DOS, 12-bit FAT */
 0x03,                 /* Ending head */
 0x11,                 /* Ending sector */
 0x00,                 /* Ending cylinder */
 0x11, 0x00, 0x00, 0x00,  /* Starting sector number*/
 0x00, 0x00, 0x00, 0x00,  /* Number of sectors */

                                     0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA

};                                                             

   
/* WriteBuf() *********************************************** */

/* Writes the given number of sectors from 'buf' to the output file */
 
static int WriteBuf( int n )
{
  if ( fwrite( buf, SECT_SIZE, n, outfile ) != n )
  {
    fclose(outfile);
    err ("Unable to write to file");
    exit(1);
  }
  return n;
}

/* WriteZeroes() ******************************************** */

/* Writes the given number of zero sectors to the output file */

static void WriteZeroes( int count )
{                           
  if ( count > BUF_SECTS )
    memset ( buf, 0, sizeof(buf) );
  else
    memset ( buf, 0, count * SECT_SIZE );
 

  while ( count > 0 )
  {
    count -= WriteBuf ( count > BUF_SECTS ? BUF_SECTS : count );
  }                
}

   
/* MakeSerialNo() function ********************************** */

/* Hashes a filename to a 32-bit volume number ************* */

static int MakeSerialNo ( char * name )
{
  int res = 0x12345678;
  int mult = 0x29BF;

  while ( *name != 0 )
  {
    res ^= ((int)*name * mult );
    mult += 0x100;
    name++;
  }

  return res;
}           

/* PhysToLogical() function ********************************* */

static int PhysToLogical ( struct DiskAddress d )
{
  return (d.sect-1) + nsects * ( d.head + nheads * d.cyl );
}
                                                                
/*  SetBytes() ********************************************** */

static void SetBytes( int offset, int value, int nbytes )
{
  while ( nbytes-- > 0 )
  {
    buf[offset++] = LSB(value);
    value = value >> 8;
  }
}


/*  WritePartitionTable() *********************************** */

static void WritePartitionTable()
{
  memcpy ( buf, DefaultPartitionTable, SECT_SIZE );                   

  buf [0x1BF ] =  Part_Start.head;         /* Starting head */
  buf [0x1C0 ] =  Part_Start.sect          /* Starting sector */
                   + ( MSB(Part_Start.cyl) << 6 );
  buf [0x1C1 ] =  LSB(Part_Start.cyl);     /* Starting cylinder */

  buf [0x1C2]  =  part_type;

  buf [0x1C3 ] =  Part_End.head;           /* Ending head */
  buf [0x1C4 ] =  Part_End.sect            /* Ending sector */
                   + ( MSB(Part_End.cyl) << 6 ); 
  buf [0x1C5 ] =  LSB(Part_End.cyl);       /* Ending cylinder */
                        
  SetBytes( 0x1C6, part_start, 4 );        /* Starting sector */
  SetBytes( 0x1CA, part_size, 4 );
   
  WriteBuf(1);                /* Write partition table boot sector */
}            
             
/* WriteBootSector() **************************************** */
                                                    
static void WriteBootSector()
{
  if ( part_type != DOS5 )
  {
    memcpy ( buf, DOS3BootSector, SECT_SIZE ); 
    SetBytes ( 0x1C, part_start, 2);         /* No. of 'hidden' sects */
    SetBytes ( 0x13, part_size, 2 );         /* Size of partition */ 
  }
  else
  {
    memcpy ( buf, DOS5BootSector, SECT_SIZE ); 
    SetBytes ( 0x1C, part_start, 4);         /* No. of 'hidden' sects */
    SetBytes ( 0x20, part_size, 4 );         /* Size of partition */ 
    SetBytes ( 0x27, vol_serialno, 4 );      /* Volume serial no. */
  }

  SetBytes ( 0x0D, cluster_size, 1);       /* Cluster size */
  SetBytes ( 0x16, FAT_size, 2 );          /* Size of each FAT */
  SetBytes ( 0x18, nsects, 2 );            /* Sectors per track */
  SetBytes ( 0x1A, nheads, 2 );            /* Number of heads */
  WriteBuf(1);
                                                      
}

/* WriteOneFAT() ******************************************** */

/* A FAT simply needs to contain FFF8 and FFFF as its first two
   entries. In a 12-bit FAT this takes 3 bytes, in a 16-bit FAT it
   takes 4.
*/             

static void WriteOneFAT()
{
  memset ( buf, 0, SECT_SIZE );  /* Clear buffer */

  if ( part_type == DOS33_SMALL )  /* If 12 bit FAT */
    SetBytes ( 0x00, 0xFFFFF8, 3 );
  else
    SetBytes ( 0x00, 0xFFFFFFF8, 4 );

  WriteBuf(1);
  WriteZeroes ( FAT_size - 1 );
}



/* FormatDisk () *********************************************** */

static void FormatDisk ()
{                                                                       
  int i;
  /* Partition table is at start of disk */

  fseek ( outfile, 0, SEEK_SET );
  WritePartitionTable();                /* Write partition table */
  WriteZeroes ( part_start - 1 );        /* & move to start of DOS area */

  /* Boot sector is at start of DOS parition */
  WriteBootSector();             /* Writes 1 sector */
                                                          
  /* Write FATs after boot sector *********** */

  for (i=0; i<NFATs; i++ )   /* Writes NFATs * FAT_size sectors */    
    WriteOneFAT();          

  /* Write blanks for root directory */

  WriteZeroes (ROOT_DIR_SECTS);

}


/* SetParameters() ***************************************************** */

/* Sets disk_size, part_size, Part_Start, Part_End, cluster_size, FAT_size */
/* given approx_size in sectors */

static BOOL SetParameters ( int approx_size )
{
  int tmp;
                                    
  /* Use Acorn PCEM 1.80 algorithm for heads/sects/tracks mapping */
      
  nsects = 17;

  for ( nheads=4; nheads < 0xFF; nheads += 2 )
  {  
    ntracks = approx_size / (nheads * nsects);
     if ( ntracks <= 1024 )
       break;
  }

  if ( nheads >= 0xFF || approx_size <= 0 )
  {
    err ("Disk dize too big");
    return FALSE;
  }

  disk_size = nheads * ntracks * nsects;                                 
  

  /* Work out how many tracks in DOS partition ************** */

  Part_Start.head = 1;
  Part_Start.sect = 1;
  Part_Start.cyl  = 0;
  Part_End.head = nheads-1;
  Part_End.sect = nsects;
  Part_End.cyl  = ntracks-1;

  /* Calculate partition addresses and size ****************** */
                             
  part_size  = PhysToLogical(Part_End) - PhysToLogical(Part_Start) + 1;
  part_start = PhysToLogical(Part_Start);                                
    

  if ( part_size < (4085*8) )        /* Use 12-bit FAT */
  {                        
    part_type = DOS33_SMALL;
    cluster_size = 8; 
    tmp = (part_size/8) + 2;            /* number of FAT entries */
    FAT_size = (tmp+339)/340;           /* 340 entries per sector */
  }
  else if ( part_size < 65535 )
  {              
    part_type = DOS33_BIG;               /* Use 16-bit FAT */            
               
    cluster_size = 4;
    tmp = (part_size/4) + 2;
    FAT_size = (tmp+255)/256;
  }
  else
  {

    /* Pick cluster size to give < 65518 clusters */
    for ( cluster_size=4; part_size >= cluster_size*65518; cluster_size *= 2 ) ;

    part_type = DOS5;           
    tmp = (part_size/cluster_size) + 2;      /* FAT holds all clusters + 2 */
    FAT_size = (tmp+255)/256;
  }

  return TRUE;
}

/* ************************************ */

static BOOL MakeFile ( char *filename, int size )
{
  _kernel_swi_regs R;
  /* First we see if the file already exists, if it does then we delete it 
  (needs filetype changed first to defeat GuardDD). 
  Then we create the new one.*/

  R.r[0] = 5;
  R.r[1] = (int) filename;
  if ( _kernel_swi ( OS_File, &R, &R ) != NULL )
  {
    err("Unable to check if file exists - attempting to continue");
  }
  
  if (R.r[0] != 0) /* file exists */
  {
    /* In case GuardDD is present - change the file type before deletion */
    R.r[0] = 18;
    R.r[1] = (int) filename;
    R.r[2] = 0xFFF;        /*text*/
    if ( _kernel_swi ( OS_File, &R, &R ) != NULL )
    {
      err("Couldn't change filetype in order to overwrite partiton");
      return FALSE;
    }
  
    R.r[0] = 6;            /* Delete file if already exists */
    R.r[1] = (int) filename;
    if ( _kernel_swi ( OS_File, &R, &R ) != NULL )
    {
      err("Couldn't delete old partition file");
      return FALSE;
    }
  }
  
  R.r[0] = 11;            /* Create file with type <R2> */
  R.r[1] = (int) filename;
  R.r[2] = 0xFC8;         /* DOS disk */
  R.r[4] = 0;
  R.r[5] = size;

  if ( _kernel_swi ( OS_File, &R, &R ) != NULL )
  {
    err("Couldn't create file");
    return FALSE;
  }

  return TRUE;
}                 

/* Main routine ***************************************************** */

BOOL CreateDisk ( char *filename, int size_MB, BOOL InitForDOS )
{    
  if ( !SetParameters(size_MB * 1956) )
    return FALSE;
                   
  if ( !MakeFile (filename, disk_size * SECT_SIZE) )
    return FALSE;

  outfile = fopen ( filename, "r+b" );
  if (outfile==NULL)
  {
    err("Couldn't re-open file for writing");
    return FALSE;
  }

  if ( InitForDOS )    
  {
    vol_serialno = MakeSerialNo ( filename );
    FormatDisk();               
  }
  else
    WriteZeroes(1);   /* Zero out partition table */

  fclose(outfile);

  return TRUE;
}

 
