/* FormatZIP V 0.1 - format a Iomega ZIP drive for PC
   1998 by Alexander Feigl - freely distributable as long as
   my name is not removed from the distributiojn               */

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

#include <exec/devices.h>
#include <exec/io.h>
#include <exec/ports.h>
#include <exec/memory.h>
#include <exec/semaphores.h>

#include <dos/exall.h>

#include <utility/tagitem.h>


#include <clib/exec_protos.h>
#include <clib/dos_protos.h>



struct MsgPort *IOPort;
struct IOStdReq *IORequest;


const unsigned char MasterBootRecord[]=
 {
  0xeb,0x2e,0x49,0x50,0x41,0x52,0x54,0x20,0x63,0x6f,0x64,0x65,0x20,0x30,0x30,0x39,
  0x20,0x2d,0x20,0x49,0x6f,0x6d,0x65,0x67,0x61,0x20,0x43,0x6f,0x72,0x70,0x6f,0x72,
  0x61,0x74,0x69,0x6f,0x6e,0x20,0x2d,0x20,0x31,0x31,0x2f,0x32,0x33,0x2f,0x39,0x30,
  0xfa,0xfc,0x8c,0xc8,0x8e,0xd0,0xbc,0x00,0x7c,0x8e,0xd8,0x8e,0xc0,0xb9,0x00,0x02,
  0xbf,0x00,0x7e,0xbe,0x00,0x7c,0xf3,0xa4,0xe9,0x00,0x02,0xfb,0xbd,0x00,0x7e,0x8b,
  0xfd,0xbe,0xbe,0x01,0xb9,0x04,0x00,0x80,0x3a,0x80,0x74,0x0b,0x83,0xc6,0x10,0xe2,
  0xf6,0x8b,0xb5,0xb2,0x01,0xeb,0x51,0x56,0x83,0xc6,0x10,0x49,0xe3,0x0b,0x80,0x3a,
  0x80,0x75,0xf5,0x8b,0xb5,0xb0,0x01,0xeb,0x3f,0x5e,0x56,0x8a,0x12,0x8a,0x72,0x01,
  0x8a,0x4a,0x02,0x8a,0x6a,0x03,0xbb,0x00,0x7c,0xbe,0x05,0x00,0x56,0xb8,0x01,0x02,
  0xcd,0x13,0x73,0x0e,0x33,0xc0,0xcd,0x13,0x5e,0x4e,0x75,0xf0,0x8b,0xb5,0xb4,0x01,
  0xeb,0x16,0x5e,0xbe,0xfe,0x7d,0x81,0x3c,0x55,0xaa,0x74,0x06,0x8b,0xb5,0xb6,0x01,
  0xeb,0x06,0x5e,0x03,0xf5,0xe9,0x48,0xfd,0xe8,0x1b,0x00,0x8b,0xb5,0xb8,0x01,0xe8,
  0x14,0x00,0xb4,0x00,0xcd,0x16,0x33,0xc0,0x8e,0xc0,0x26,0xc7,0x06,0x72,0x04,0x34,
  0x12,0xea,0xf0,0xff,0x00,0xf0,0x03,0xf5,0xac,0x3c,0x00,0x74,0x0b,0x56,0xb4,0x0e,
  0xbb,0x07,0x00,0xcd,0x10,0x5e,0xeb,0xf0,0xc3,0x49,0x6e,0x76,0x61,0x6c,0x69,0x64,
  0x20,0x70,0x61,0x72,0x74,0x69,0x74,0x69,0x6f,0x6e,0x20,0x74,0x61,0x62,0x6c,0x65,

  0x00,0x44,0x69,0x73,0x6b,0x20,0x69,0x73,0x20,0x6e,0x6f,0x74,0x20,0x62,0x6f,0x6f,
  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,0x0d,0x0a,
  0x52,0x65,0x70,0x6c,0x61,0x63,0x65,0x20,0x61,0x6e,0x64,0x20,0x73,0x74,0x72,0x69,
  0x6b,0x65,0x20,0x61,0x6e,0x79,0x20,0x6b,0x65,0x79,0x20,0x77,0x68,0x65,0x6e,0x20,
  0x72,0x65,0x61,0x64,0x79,0x0d,0x0a,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,0x1a,0x06,
  0xe9,0x00,0x01,0x01,0x16,0x01,0x35,0x01,0x4e,0x01,0xd5,0xb5,0xc7,0x79,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,0x01,
  0x01,0x00,0x06,0x3f,0x20,0x5f,0x20,0x00,0x00,0x00,0xe0,0xff,0x02,0x00,0x55,0xaa
 };

const unsigned char BootBlock[]={
  0xeb,0x3c,0x90,0x5a,0x49,0x50,0x46,0x4d,0x54,0x20,0x20,0x00,0x02,0x08,0x01,0x00,
  0x02,0x00,0x02,0x00,0x00,0xf8,0x60,0x00,0x20,0x00,0x40,0x00,0x20,0x00,0x00,0x00,
  0xe0,0xff,0x02,0x00,0x00,0x00,0x29,0xbc,0x07,0x4d,0x37,0x5a,0x49,0x50,0x2d,0x31,
  0x30,0x30,0x20,0x20,0x20,0x20,0x46,0x41,0x54,0x31,0x36,0x20,0x20,0x20,0xfb,0x31,
  0xc0,0x8e,0xd0,0x8e,0xd8,0xbc,0x00,0x7c,0xbe,0x59,0x7c,0xb4,0x0e,0xbb,0x07,0x00,
  0xac,0x84,0xc0,0x74,0xfe,0xcd,0x10,0xeb,0xf7,0x5a,0x49,0x50,0x46,0x6f,0x72,0x6d,
  0x61,0x74,0x20,0x20,0x20,0x20,0x6e,0x6f,0x6e,0x2d,0x62,0x6f,0x6f,0x74,0x61,0x62,
  0x6c,0x65,0x20,0x64,0x69,0x73,0x6b,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
 }; 


int WriteBlock(unsigned long block,const unsigned char *blockptr)
 {
  IORequest->io_Command=CMD_WRITE;
  IORequest->io_Flags=0;
  IORequest->io_Length=512;
  IORequest->io_Data=(APTR) blockptr;
  IORequest->io_Offset=block<<9;
  
  DoIO(((struct IORequest *) IORequest));
  if (IORequest->io_Error) return(1);
  return(0);
 }


void Cleanup()
 {
  CloseDevice(((struct IORequest *) IORequest));
  DeleteIORequest(IORequest);
  DeleteMsgPort(IOPort);

 }

int main(int argc,char **argv)
 {
  unsigned char device[64];
  unsigned long unit;

  printf("FormatZIP V0.1 - Format ZIPs for PC\n1998 by Alexander Feigl <sp7ock@dl-net.de>\n");

  if (argc!=3)
   {
    printf("Usage : %s <device> <unit>\n",argv[0]);
    exit(20);
   }
  strcpy(device,argv[1]);
  sscanf(argv[2],"%ld",&unit);
  if ( (unit<0) || (unit>1024))
   {
    puts("Invalid parameters!");
    exit(20);
   }

  /* Open exec device for direct access to the ZIP drive */
  
  IOPort=CreateMsgPort();
  if (IOPort==NULL)
   {
    puts("Cannot create msg port!");
    exit(20);
   }
  IORequest=CreateIORequest(IOPort,sizeof(*IORequest));
  if (IORequest==NULL)
   {
    DeleteMsgPort(IOPort);
    puts("Cannot create IO Request!");
    exit(20);
   }
  if (OpenDevice(device,unit,((struct IORequest *) IORequest),0))
   {
    DeleteIORequest(IORequest);
    DeleteMsgPort(IOPort);
    puts("Cannot open device driver!");
    exit(20);
   }

  /* Write Master Boot Record - I got it from a FujiFilm ZIP-100 disk
     write first block from array - pad rest of MBR with 0x48          */

  puts("Writing Master Boot Record (MBR) ...");

  if (WriteBlock(0,MasterBootRecord))
   {
    puts("Cannot write MBR!");
    Cleanup();
    exit(20);
   }
   {  
    unsigned char mbrpad[512];
    unsigned long i;
    for (i=0;i<512;++i) mbrpad[i]=0x48;
    for (i=1;i<32;++i) 
     {
      if (WriteBlock(i,mbrpad))
       {
        puts("Cannot write MBR padding!");
        Cleanup();
        exit(20);
       }
     }
   }

  Cleanup();
  exit(20);

  
  /* write ZIP bootblock - first part from array - pad with 0 
     NOTE : the volume ID is initialized with random numbers so that
            the filesystem can distinguish between different ZIPs     */

  puts("Writing boot record ...");
   {
    unsigned char boot[512];
    unsigned long i;
    
    for (i=128;i<512;++i) boot[i]=0x0;

    for (i=0;i<128;++i) boot[i]=BootBlock[i];
    boot[510]=0x55;
    boot[511]=0xaa;

    /* randomize volume ID */

    srand(time(NULL));
    boot[39]= (rand()%256);
    boot[40]= (rand()%256);
    boot[41]= (rand()%256);
    boot[42]= (rand()%256);

    if (WriteBlock(32,boot))
     {
      puts("Cannot write bootblock!");
      Cleanup();
      exit(20);
     }

   }

  /* write ZIP FAT - it is padded with 0-bytes - only the first four 
     bytes of the both FATs have do be initalized differently        */

  puts("Wrinting File Allocation Table (FAT) ...");
   {
    unsigned char fat[512];
    unsigned long i,j;
    for (j=33;j<225;++j)
     {
      for (i=0;i<512;++i) fat[i]=0x0;
      if ( (j==33) || (j==129))
       {
        fat[0]=0xf8;
        fat[1]=0xff;
        fat[2]=0xff;
        fat[3]=0xff;
       }

      if (WriteBlock(j,fat))
       {
        puts("Cannot write FAT!");
        Cleanup();
        exit(20);
       }
     }
 
   }

  /* write ZIP root directory - it's padded with 0-bytes except the first
     directory entry which is the disk label                             */

  puts("Writing root directory ...");

   {
    unsigned char dir[512];
    unsigned long i,j;
    for (j=225;j<257;++j)
     {
      for (i=0;i<512;++i) dir[i]=0x0;
      if (j==225)
       {
        memcpy(dir,"ZIP-100    ",11);
        dir[11]=0x28;
        dir[22]=0xf4;
        dir[23]=0x72;
        dir[24]=0x7c;
        dir[25]=0x24;

       }

      if (WriteBlock(j,dir))
       {
        puts("Cannot write root directory!");
        Cleanup();
        exit(20);
       }
     }


   }

  /* Close the exec device */

  Cleanup();

  return(0);
 }


void __openliberror(void)
 {
  exit(20);
 }
