home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / diskutil / flip / flip.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-03-22  |  23.8 KB  |  995 lines

  1. /********************************************\
  2. *                          *
  3. * flip: Unprotected disk copier             *
  4. * By Colas NAHABOO (INRIA sophia-antipolis)  *
  5. *                          *
  6. * Compile with MEGAMAX C v1.1 (in-line asm)  *
  7. *                         *
  8. \********************************************/
  9.  
  10. #define VERSION "2.7"
  11. #define DATE    "Jun 25 88"
  12.  
  13. char           *header =
  14. "\33E\33e\33v\033p\
  15. FLIP: disk copier by Colas Nahaboo     v%-5s %-9s           Free Ram:%4ldK\
  16. \033q\n\n";
  17.  
  18. #include <osbind.h>
  19. #include <stdio.h>
  20.  
  21. #define BLANK (0xE5E5)        /* std sector format value */
  22. #define MAGIC (0x87654321L)    /* magic number value */
  23. unsigned char *ROMS_YEAR = 0x00fc0018L + 3L; /* year of the roms */
  24. #define MEMORY_LEFT 0        /* bytes not eaten by main buffer */
  25. #define TRACK_RETRY 4        /* number of full track retrys */
  26. #define NO_DISK        0    /* no disk in drive */
  27. #define SOURCE_DISK    1    /* source disk in drive */
  28. #define DEST_DISK    2    /* destination disk in drive */
  29.  
  30.                 /* list of fatal errors */
  31. #define NORMAL        10
  32. #define USER_ABORT    1
  33. #define SYNTAX_ERROR    2
  34. #define NO_DISK_IN_MEMORY 3
  35. #define NO_OVERRIDE    4
  36. #define NO_DRIVE_B    5
  37. #define DOUBLE_ON_BACK    6
  38. #define NO_FLIP_ON_DOUBLE 7
  39. #define BAD_OPTION    8
  40. #define NO_MEMORY    9
  41.  
  42. int bad_option    =    ' ';
  43.  
  44. /* twister interface */
  45. extern          twister();    /* adress of formatter */
  46. char            buffer_data[0x3FFF];    /* 16k of buffer */
  47. extern long     buffer;        /* format track buffer */
  48. extern int      thedisk,    /* A=0, B=1 */
  49.                 dblsided,    /* SS=0, DS= -1 */
  50.                 sectoroffset,    /* 0 = sectors 0 to 10, 1= 11 to 20 */
  51.                 flipped,    /* normal=0, back side=1 */
  52.         keypress,    /* 1 if key aborted format */
  53.                 starttrack,    /* 0 or more */
  54.                 endtrack;    /* 80 or more */
  55. extern int      badflag;    /* return code */
  56. extern int    new_roms;    /* are we running with the new roms? */
  57.  
  58. /* flip's globals */
  59. long            buffer_size = 0L;    /* max size of buffer */
  60. jmp_buf         start_dest;    /* insert dest */
  61. int        drives_content[2];/* what is there in the drives ? */
  62.  
  63. int                /* disk parameters read from boot sect */
  64.                 drive,        /* drive: 0=A, 1=B */
  65.                 sides,        /* 0=SS, 1=DS */
  66.                 tracks,        /* 80 normally */
  67.                 st,        /* sectors per track (9 or 10) */
  68.                 bps;        /* bytes per sector (512) */
  69.  
  70. int                /* options */
  71.         verify_source,     /* just verify the source */
  72.         read_source,    /* read source */
  73.         zero_disk,    /* prepares blank image in memory */
  74.         write_dest,    /* write dest */
  75.                 format,        /* do format */
  76.                 Verify,        /* do verify formatting */
  77.                 verify,        /* do verify writing */
  78.         override,    /* do not read boot sector */
  79.         single,        /* Single Sided */
  80.         nine_sectors,    /* 9 sect/track */
  81.                 interactive,    /* interactive */
  82.         play_it_again_sam, /* user hit "return" */
  83.                 use_track_map;    /* to use built-in track map */
  84.  
  85. int             d1=0, d2=0, s1=0, s2=0; /* drive/side source/dest */
  86.  
  87. #define TRACK_MAP_SIZE    99
  88. char            track_map[TRACK_MAP_SIZE + 1];
  89. char            full_track_map[TRACK_MAP_SIZE + 1]; /* for multipasses */
  90.  
  91. int             one_valid_copy_done = 0;    /* used to allow "r" */
  92. int             multipass;    /* when not enough mem */
  93. int        first_pass,
  94.         last_pass;
  95.  
  96. jmp_buf         start;
  97. char           *buf = NULL;
  98. char           *malloc(), *index(), *get_drive();
  99. unsigned    is_non_executable();
  100. extern char    *help_text[];
  101. int             errno;
  102.  
  103. char            rep[40], default_rep[40]; /* input buffer */
  104.  
  105. /*
  106.  * parse the command line and set options
  107.  * return 1 if error, 0 if OK
  108.  */
  109.  
  110. int
  111. parse_command()
  112. {
  113.     printf("Command (? for help) (CR= %s ): ", default_rep);
  114.     fflush(stdout);
  115.     gets(rep);
  116.      /* parse main options */
  117.     verify_source = read_source = zero_disk = write_dest = format =
  118.     verify = Verify = use_track_map = override = nine_sectors = single =
  119.     interactive = d1 = d2 = s1 = s2 = play_it_again_sam = 0;
  120.     if (!rep[0]) {        /* void rep ==> default */
  121.         strcpy(rep, default_rep);
  122.         play_it_again_sam = 1;
  123.     }
  124.     switch(rep[0]){
  125.     case '?':        /* need help */
  126.         more(help_text);
  127.         longjmp(start, NORMAL);
  128.     case 'q':        /* quit */
  129.         exit(0);
  130.     case 'v':
  131.         verify_source = 1;
  132.         get_options(get_drive(SOURCE_DISK, rep+1, 1), "os9ti");
  133.         return 0;
  134.     case 'r':
  135.         if (!one_valid_copy_done) 
  136.         longjmp(start, NO_DISK_IN_MEMORY);
  137.         get_options(get_drive(DEST_DISK, rep+1,1), "fvVi");
  138.         write_dest = 1;
  139.         return 0;
  140.     case 'f':
  141.         override = 1;
  142.         get_options(get_drive(DEST_DISK, rep+1,1), "s9tvVfi");
  143.         zero_disk = 1;
  144.         write_dest = 1;
  145.         return 0;
  146.     case 'a': case 'b':
  147.         get_options(
  148.         get_drive(DEST_DISK,
  149.               get_drive(SOURCE_DISK, rep, 0),
  150.               1),
  151.         "os9tvVfi");
  152.         read_source = write_dest = 1;
  153.         return 0;
  154.     default :
  155.         longjmp(start, SYNTAX_ERROR);
  156.     }
  157. }
  158.  
  159. char *
  160. get_drive(drive, string, is_optional)
  161. int drive;
  162. char * string;
  163. int is_optional;
  164. {
  165.     char *ptr =string;
  166.     int side = 0, default_drive = 0;
  167.  
  168.     if(!index("abAB", string[0])) 
  169.         if(is_optional)
  170.         default_drive = 1;        /* drive A is default */
  171.     else
  172.         longjmp(start, SYNTAX_ERROR);
  173.     if(!default_drive && (index("12", string[1]))) {
  174.     ptr ++;
  175.     side = (toupper(*ptr) == '2' ? 1 : 0);
  176.     }
  177.     if(drive == DEST_DISK){
  178.     d2 = (default_drive ? 0 : (toupper(*string) == 'B' ? 1 : 0));
  179.     s2 = side;
  180.     }else{
  181.     d1 = (default_drive ? 0 : (toupper(*string) == 'B' ? 1 : 0));
  182.     s1 = side;
  183.     }
  184.     return (default_drive ? string : ptr +1);
  185. }
  186.  
  187. get_options(string, options)
  188. char *string, *options;
  189. {
  190.     while(*string){
  191.     if(!index(options, *string)) {
  192.         bad_option = *string;
  193.         longjmp(start, BAD_OPTION);
  194.     }
  195.     switch(*string){
  196.     case 'o': override = 1; break;
  197.     case 's': single = 1; break;
  198.     case '9': nine_sectors = 1; break;
  199.     case 't': use_track_map = 1; break;
  200.     case 'v': verify = 1; break;
  201.     case 'V': Verify = 1; break;
  202.     case 'f': format = 1; break;
  203.     case 'i': interactive = 1; break;
  204.     }
  205.     string++;
  206.     }
  207.     if(!override && (single || nine_sector)) 
  208.     longjmp(start, NO_OVERRIDE);
  209. }
  210.  
  211. main()
  212. {
  213.  
  214.     buffer = (long) buffer_data;/* init twister */
  215.     sectoroffset = 0;        /* mem alloc */
  216.     buffer_size = (long) Malloc(-1L) - MEMORY_LEFT;
  217.     buf = (char *) Malloc(buffer_size);
  218.     if(((unsigned) *ROMS_YEAR) > (unsigned) 0x86)
  219.     new_roms = 1;
  220.     else
  221.     new_roms = 0;
  222.     if(is_drive_B())        /* default command */
  223.         strcpy(default_rep, "bfv");
  224.     else
  225.         strcpy(default_rep, "afv");
  226.     printf(header, VERSION, DATE, buffer_size / 1024);    /* resets screen */
  227.     switch(setjmp(start)){
  228.     case 0:case NORMAL:            /* initial */
  229.     break;
  230.     case USER_ABORT:            /* user abort */
  231.     printf("\007Ok, aborted...\n");
  232.     break;
  233.     case SYNTAX_ERROR:            /* syntax error */
  234.     printf("\007SYNTAX ERROR!\n");
  235.     break;
  236.     case NO_DISK_IN_MEMORY:
  237.     printf("\007No disk in memory!\n");
  238.     break;
  239.     case NO_OVERRIDE:
  240.         printf("\007Options d and 9 requires option o\n");
  241.     break;
  242.     case NO_DRIVE_B:
  243.     printf("\007Sorry, no drive B present...\n");
  244.     break;
  245.     case DOUBLE_ON_BACK:
  246.     printf("\007A double sided disk on back? use override!\n");
  247.     break;
  248.     case NO_FLIP_ON_DOUBLE:
  249.     printf("\007You cannot flip double-sided disks!\n");
  250.     break;
  251.     case BAD_OPTION:
  252.     printf("\007bad option: %c\n", bad_option);
  253.     break;
  254.     case NO_MEMORY:
  255.     printf("\007Sorry, not enough memory...\n");
  256.     break;
  257.     }
  258.     while (1) {
  259.     /* we dont know what's in the drives */
  260.     drives_content[0] = drives_content[1] = NO_DISK;
  261.     /* prompts and parse command and options */
  262.     parse_command();
  263.     /* check for drive B */
  264.     if ((d1 || d2) && (!is_drive_B()))
  265.         longjmp(start, NO_DRIVE_B);
  266.     /* prompts for track_map */
  267.     if (use_track_map)
  268.         input_track_map();
  269.     /* examine source disk */
  270.     if(read_source || verify_source || zero_disk)
  271.             examine_disk(d1, s1);
  272.     /* check run time consistency */
  273.     if (sides == 2) {
  274.         if (s1 == 1) 
  275.             longjmp(start, DOUBLE_ON_BACK);
  276.         if (s1 != s2) 
  277.         longjmp(start, NO_FLIP_ON_DOUBLE);
  278.     }
  279.     strcpy(default_rep, rep);    /* seems ok then take it as default */
  280.  
  281.        /* copy disk */
  282.     if((d1 != d2) &&     /* suppose user had time to put dest */
  283.         (read_source || verify_source))
  284.         drives_content[d2] = DEST_DISK;
  285.     do_copy_disk();
  286.     printf("\007OK, done.\n");
  287.     }
  288. }
  289.  
  290. /*
  291.  * do_copy_disk:
  292.  * do a one-pass or multipass copy 
  293.  */
  294.  
  295. do_copy_disk()
  296. {
  297.     int             track_number = 0, i, j, to_do;
  298.  
  299.     multipass = 0;
  300.     if (read_source) {
  301.         for (i = 0; i < TRACK_MAP_SIZE; i++)
  302.         track_number += (int) track_map[i];
  303.         if(buffer_size < (sides * bps * st * (long) track_number))
  304.             multipass = 1;
  305.         one_valid_copy_done = !multipass; /* let previous value of
  306.             multipass inchanged if no read_source */
  307.     }
  308.     if(zero_disk) one_valid_copy_done = 0;
  309.     bcopy(track_map, full_track_map, TRACK_MAP_SIZE);
  310.     if(!multipass){
  311.         copy_disk();
  312.     }else{
  313.         for(j=0; j<TRACK_MAP_SIZE; j++)
  314.         track_map[j] = '\0';
  315.         track_number = buffer_size / (sides*bps*st);
  316.         i = to_do = 0;
  317.         first_pass = 1;
  318.         last_pass  = 0;
  319.         while(i < TRACK_MAP_SIZE){
  320.         if(full_track_map[i]){
  321.             to_do++;
  322.             track_map[i] = '\001';
  323.         }
  324.         if(to_do == track_number){
  325.             copy_disk();
  326.             to_do = first_pass = 0;
  327.             for(j=0; j<TRACK_MAP_SIZE; j++)
  328.             track_map[j] = '\0';
  329.         }
  330.         i++;
  331.         }
  332.         first_pass = 0;
  333.         last_pass = 1;
  334.         copy_disk();
  335.     }
  336. }
  337.  
  338.  
  339. /*
  340.  * examine_disk: reads boot sector to determine type of disk.
  341.  */
  342.  
  343. /* describe the BOOT sector by offsets in the boot sector */
  344. #define b_bootbranch 0
  345. #define b_oem 0x02
  346. #define b_serial 0x08
  347. #define b_bps 0x0B
  348. #define b_spc 0x0D
  349. #define b_res 0x0E
  350. #define b_nfats 0x10
  351. #define b_ndirs 0x11
  352. #define b_nsects 0x13
  353. #define b_media 0x15
  354. #define b_spf 0x16
  355. #define b_spt 0x18
  356. #define b_nsides 0x1A
  357. #define b_nhide 0x1C
  358. #define b_boot 0x1E
  359. #define b_checksum 0x01FE
  360.  
  361. /* 2 chars ==> 1 int */
  362. #define canshort(x,y) (((unsigned)(x))|(((unsigned)(y))<<8))
  363.  
  364. unsigned char   bb[512];
  365.  
  366. randomize_boot()
  367. {
  368.     long serial;
  369.     unsigned non_exec = is_non_executable(buf);
  370.  
  371.     if((!multipass || first_pass) && track_map[0]) {
  372.     serial = Random();
  373.     buf[b_serial] = (char) ((serial >> 16) & 255L);
  374.     buf[b_serial+1] = (char) ((serial >> 8) & 255L);
  375.     buf[b_serial+2] = (char) (serial & 255L);
  376.     update_checksum(buf, non_exec);
  377.     }
  378. }
  379.  
  380. /*
  381.  * prepares a blank image:
  382.  * boot sector, & zero tracks 0&1 (if enough memory)
  383.  */
  384.  
  385. do_zero_disk()
  386. {
  387.     unsigned nsects;
  388.  
  389.     if(buffer_size < (sides * bps * st * 2L)) longjmp(start, NO_MEMORY);
  390.     bfill(buf, '\0', (long) (sides * bps * st * 2L));
  391.     Protobt(buf, 0x02000000L, ((sides == 2) ? 3 : 2), 0);
  392.     buf[b_spt] = (char) (st & 0xFF);
  393.     nsects = (unsigned) (sides * st * (1 + max_track()));
  394.     buf[b_nsects] = (char) (nsects & 255);
  395.     buf[b_nsects+1] = (char) ((nsects >> 8) & 255);
  396.     update_checksum(buf, (unsigned) 1);
  397.     printf("Formatting %s sided disk, %d tracks and %d sectors.\n",
  398.     ((sides == 1) ? "single" : "double"), 1+max_track(), st);
  399. }
  400.  
  401. int
  402. max_track()
  403. {
  404.     int i;
  405.  
  406.     for (i= TRACK_MAP_SIZE -1; i>=0; i--)
  407.     if(full_track_map[i]) return i;
  408.     return 0;
  409. }
  410.  
  411. examine_disk(drive, side)
  412. int             drive, side;
  413. {
  414.     int             i;
  415.  
  416.     if (override) {
  417.     sides = (single ? 1 : 2);
  418.     bps = 512;
  419.     st = (nine_sectors ? 9 : 10);
  420.     tracks = 80;
  421.     } else {
  422.         if (drives_content[drive] != SOURCE_DISK) {
  423.         prompt_for_disk(SOURCE_DISK, drive, side);
  424.         }
  425.     while (Floprd(&bb, 0L, drive, 1, 0, side, 1)) {
  426.         printf("\007Cannot read boot block! CR/SP=retry, other=abort: ");
  427.         fflush(stdout);
  428.         if (!index("\r\n ", (char) Cnecin()))
  429.         longjmp(start, USER_ABORT);
  430.     }
  431.     if(!is_non_executable(bb)) {
  432.     printf("\007EXECUTABLE BOOT! at $3A, %2x %2x %2x -- check for virus\n",
  433.         (int) bb[58], (int) bb[59], (int) bb[60]);
  434.     }
  435.     printf("Disk in drive %c:", 'A' + drive);
  436.     printf(" %d side", sides = (int) bb[b_nsides]);
  437.     printf("%s, %d tracks,", (sides == 2 ? "s" : ""),
  438.            tracks = ((canshort(bb[b_nsects], bb[b_nsects + 1]) /
  439.               (int) bb[b_spt]) /
  440.              (int) bb[b_nsides]));
  441.     printf(" %d sectors of", st = (int) bb[b_spt]);
  442.     printf(" %d bytes\n", bps =
  443.            canshort(bb[b_bps], bb[b_bps + 1]));
  444.     if ((bps != 512) || ((st != 10) && (st != 9)) || (tracks != 80)) {
  445.         printf("\007WARNING -- this is not a normal disk!\n");
  446.     }
  447.     if (sides < 1 || sides > 2 ||
  448.         bps != 512 ||
  449.         st > 11 || st < 9 ||
  450.         tracks < 1 || tracks > TRACK_MAP_SIZE) {
  451.         printf("***** Strange disk! ... copying normally ");
  452.         printf("(1 side, 80 tracks of 9 sectors)\n");
  453.         override = 1;
  454.         sides = 1;
  455.         bps = 512;
  456.         st = 9;
  457.         tracks = 80;
  458.     }
  459.     }
  460.     if (!use_track_map) {
  461.     for (i = 0; i < tracks; i++)
  462.         track_map[i] = '\001';
  463.     for (i = tracks; i < TRACK_MAP_SIZE; i++)
  464.         track_map[i] = '\0';
  465.     }
  466. }
  467.  
  468. /*
  469.  * format disk using TWISTER
  470.  * returns 0 if OK, aborts and returns 1 on error.
  471.  */
  472.  
  473. int
  474. format_disk(f_drive, f_double, f_side)
  475. int             f_drive, f_double, f_side;
  476. {
  477.     int             i;
  478.     char         *map;
  479.  
  480.     if(multipass)
  481.         map = full_track_map;
  482.     else
  483.     map = track_map;
  484.     thedisk = f_drive;
  485.     dblsided = (f_double ? -1 : 0);
  486.     flipped = f_side;
  487. redo:
  488.     i = 0;
  489.     while (i < TRACK_MAP_SIZE) {
  490.     if (map[i]) {
  491.         starttrack = i;
  492.         while (map[i++]);
  493.         endtrack = i - 1;
  494.         keypress = 0;
  495.         Supexec(twister);
  496.         if(keypress) {
  497.         longjmp(start, USER_ABORT);
  498.         }
  499.         if (badflag){
  500.         printf("\n\007FORMAT Error! CR/SP = retry whole formatting,");
  501.         printf(" other=abort\n");
  502.         printf("(disk might be WRITE_PROTECTED?)\n");
  503.         if (!index("\r\n ", (char) Cnecin()))
  504.             longjmp(start, USER_ABORT);
  505.         else
  506.             goto redo;
  507.         }
  508.     } else {
  509.         i++;
  510.     }
  511.     }
  512. }
  513.  
  514. /*
  515.  * copy_disk: where the copy is really done
  516.  */
  517.  
  518. copy_disk()
  519. {
  520.     if((read_source || verify_source)
  521.         && (drives_content[d1] != SOURCE_DISK))
  522.         prompt_for_disk(SOURCE_DISK, d1, s1);
  523.     if (read_source) {        /* source */
  524.     read_disk(d1, s1);    /* read */
  525.     next_line();
  526.     }
  527.     if (verify_source && (!multipass || first_pass)) {
  528.     verify_disk(d1, s1);
  529.     next_line();
  530.     }
  531.  
  532.     setjmp(start_dest);        /* destination */
  533.     if(zero_disk) do_zero_disk();            /* blank image */
  534.     if(!override) randomize_boot();            /* change serial */
  535.     if((format || Verify || write_dest || verify))
  536.     prompt_for_disk(DEST_DISK, d2, s2);
  537.     if (format && (!multipass || first_pass)) {        /* format */
  538.     format_disk(d2, sides - 1, s2);
  539.     next_line();
  540.     }
  541.     if (Verify && (!multipass || first_pass)) {        /* Verify */
  542.     verify_disk(d2, s2);
  543.     next_line();
  544.     }
  545.     if (write_dest) {        /* write */
  546.     write_disk(d2, s2);
  547.     next_line();
  548.     }
  549.     if (verify && (!multipass || last_pass)) {        /* verify */
  550.     verify_disk(d2, s2);
  551.     next_line();
  552.     }
  553. }
  554.  
  555. /*
  556.  * return 1 if skip, 0 if no key, longjmps to start if abort
  557.  */
  558.  
  559. abort_on_key(track,side)
  560. int             track,side;
  561. {
  562.     if (Cconis()) {
  563.     if ((int) Cnecin() == 0x1b)
  564.         longjmp(start, USER_ABORT);
  565.     printf("\n\007KEY PRESSED! CR/SP = continue, ");
  566.     printf("i=interactive, %s other abort:\n",
  567.            (track == -1 ? "" : " S = skip,"));
  568.     switch ((int) Cnecin()) {
  569.     case ' ':
  570.     case '\n':
  571.     case '\r':
  572.         return 0;
  573.     case 'i':
  574.     case 'I':
  575.         interactive = 1;
  576.         return 0;
  577.     case 's':
  578.     case 'S':
  579.         if (track != -1) {
  580.         printf("Ok, skipping track %d, side %d (sects #%d - #%d)\n",
  581.                track + 1, side +1,
  582.                ((track * sides) + side)* st,
  583.                ((track * sides) + side + 1) * st);
  584.         return 1;
  585.         }
  586.     }
  587.     longjmp(start, USER_ABORT);
  588.     }
  589. }
  590.  
  591. int
  592. retry(s, t, side, restart)
  593. char           *s;
  594. int             t, side;
  595. long           *restart;
  596. {
  597.     printf("\n\007** %s ERROR track %d ,side %d (s. #%d - #%d) ",
  598.        s, t + 1, side + 1,
  599.        (t * sides + side) * st,
  600.        (t * sides + side + 1) * st);
  601.     printf("CR/SP retry, S skip, %sother abort",
  602.        (restart ? "BS=OTHER disk " : ""));
  603.     fflush(stdout);
  604.     switch ((int) Cnecin()) {
  605.     case ' ':
  606.     case '\r':
  607.     case '\n':
  608.     return 1;
  609.     case 's':
  610.     case 'S':
  611.     printf("\n OK, skipping track %d, side %d\n", t + 1, side + 1);
  612.     return 0;
  613.     case '\010':
  614.     if (restart)
  615.         longjmp(restart, 1);
  616.     default:
  617.     longjmp(start, USER_ABORT);
  618.     }
  619. }
  620.  
  621. /*
  622.  * sector_read
  623.  * reads one track into ptr, reading sector by sector
  624.  * returns: 0=ok, 1=bad, 2= skip.
  625.  */
  626.  
  627. int
  628. sector_read(ptr, foo, drive, sect1, track, side, n)
  629. char           *ptr, *foo;
  630. int             drive, sect1, track, side, n;
  631. {
  632.     int             i, result = 0, pass;
  633.     int             pass_ok[4];
  634.  
  635.     for (pass = 0; pass < 4; pass++) {
  636.     pass_ok[pass] = 1;
  637.     for (i = 0; i < n; i++) {
  638.         if (abort_on_key(track,i))
  639.         return 2;
  640.         switch (one_sector_read(
  641.          (pass ? buffer_data + (pass - 1) * 5120 : ptr) + (i * bps),
  642.                     foo, drive, i + sect1, track, side)) {
  643.         case 1:
  644.         if (!result)
  645.             printf("\nTrack %d, side %d: sectors ",
  646.             track + 1, side + 1);
  647.         result = 1;
  648.         printf("%d (#%d) ", i + 1, (track * sides + side) * st + i);
  649.         fflush(stdout);
  650.         bfill(ptr + i * bps, '\0', (long) bps); /* fills bad sector with */
  651.                          /* 0's */
  652.         case 2:
  653.         pass_ok[pass] = 0;
  654.         }
  655.     }
  656.     if (result) {
  657.         printf("are bad!\n");
  658.         fflush(stdout);
  659.         return result;
  660.     }
  661.     }
  662.     if (pass_ok[0])
  663.     return 0;        /* if any pass is good, use it */
  664.     {
  665.     int             i;
  666.  
  667.     for (i = 1; i < 4; i++) {
  668.         if (pass_ok[i]) {
  669.         bcopy(buffer_data + 512 * (i - 1), ptr, 512 * n);
  670.         return 0;
  671.         }
  672.     }
  673.     }
  674.     if (check_random(track, side, n, ptr, buffer_data)) {
  675.     return 1;        /* random read */
  676.     } else {
  677.     printf("\nTrack %d, side %d, (sects #%d - #%d) read sect by sect\n"
  678.            ,track + 1, side + 1,
  679.            (track * sides + side) * st,
  680.            (track * sides + side + 1) * st);
  681.     return 1;        /* no but don't trust! */
  682.     }
  683. }
  684.  
  685. /*
  686.  * check_random:
  687.  * check tracks buffer to see if equal, return 1 if error
  688.  */
  689.  
  690. int
  691. check_random(track, side, n, buf0, buf1)
  692. int             track, side, n;
  693. char           *buf0, *buf1;
  694. {
  695.     int             sect, i, bad = 0;
  696.     char           *p0, *p1, *p2, *p3;
  697.  
  698.     for (sect = 1; sect <= n; sect++) {
  699.     p0 = buf0 + (sect - 1) * 512;
  700.     p1 = buf1 + (sect - 1) * 512;
  701.     p2 = buf1 + (sect - 1) * 512 + 5120;
  702.     p3 = buf1 + (sect - 1) * 512 + 10240;
  703.     for (i = 0; i < 512; i++, p0++, p1++, p2++, p3++) {
  704.         if ((*p0 != *p1) || (*p0 != *p2) || (*p0 != *p3)) {
  705.         if (!bad) {
  706.             printf("\n\007DIFFERENT READS ");
  707.             printf("on track %d, side %d, sects ",
  708.                track + 1, side + 1);
  709.             bad = 1;
  710.         }
  711.         printf("%d (#%d) ", sect,
  712.         (track * sides + side) * st + sect - 1);
  713.         break;
  714.         }
  715.     }
  716.     }
  717.     if(bad) {
  718.         printf("\n");
  719.     fflush(stdout);
  720.     }
  721.     return bad;
  722. }
  723.  
  724.  
  725. /*
  726.  * one_sector_read:
  727.  * reads a sector and the 2 outside it
  728.  * return 0 if ok, 1 if bad, 2 if forced to copy sector alone
  729.  */
  730.  
  731. char           *private_buffer[512 * 3];
  732.  
  733. int
  734. one_sector_read(buf, foo, drive, sect, track, side)
  735. char           *buf, *foo;
  736. int             drive, sect, track, side;
  737. {
  738.     if (Floprd(private_buffer + (sect == 1 ? 512 : 0), foo, drive,
  739.            (sect == 1 ? 1 : sect - 1), track, side,
  740.            ((sect == 1) || (sect == st) ? 2 : 3))) {
  741.     if (Floprd(private_buffer + 512, foo, drive, sect, track, side, 1)){
  742.         return 1;
  743.     } else {
  744.         bcopy(private_buffer + 512, buf, 512);
  745.         return 2;
  746.     }
  747.     }
  748.     bcopy(private_buffer + 512, buf, 512);
  749.     return 0;
  750. }
  751.  
  752. next_line()
  753. {
  754.     Crawio((int) '\r');
  755.     Crawio((int) '\n');
  756. }
  757.  
  758. bcopy(from, to, count)
  759. register char  *from, *to;
  760. int             count;
  761. {
  762.     register char  *last = from + count;
  763.  
  764.     while (from != last)
  765.     *to++ = *from++;
  766. }
  767.  
  768. bfill(from, octet, count)
  769. register char  *from, octet;
  770. long             count;
  771. {
  772.     register char  *last = from + count;
  773.  
  774.     while (from != last)
  775.     *from++ = octet;
  776. }
  777.  
  778. /*
  779.  * is_drive_B
  780.  * return 1 if drive B is there
  781.  */
  782.  
  783. int 
  784. is_drive_B()
  785. {
  786.     long            usermode = Super(0L);
  787.     int             result = *(int *) 0x4a6;    /* _nflops */
  788.  
  789.     Super(usermode);
  790.     return (result - 1);
  791. }
  792.  
  793. /*
  794.  * retry_track
  795.  * retries plain track
  796.  */
  797.  
  798. int 
  799. retry_track(track, side)
  800. int             track, side;
  801. {
  802.     printf("\n\007** Track-read error track %d ,side %d \n", track + 1, side + 1);
  803.     printf("CR/SP retry, ESC aborts, other go to sector_read: ");
  804.     fflush(stdout);
  805.     switch ((char) Cnecin()) {
  806.     case ' ':
  807.     case '\r':
  808.     return 1;
  809.     case 0x1b:
  810.     longjmp(start, USER_ABORT);
  811.     default:
  812.     return 0;
  813.     }
  814. }
  815.  
  816. verify_disk(drive, side)
  817. int             drive, side;
  818. {
  819.     char           *ptr, *map;
  820.     int             t, n;
  821.  
  822.     if(multipass)
  823.         map = full_track_map;
  824.     else
  825.     map = track_map;
  826.     ptr = buffer_data;
  827.     for (t = 0; t < TRACK_MAP_SIZE; t++) {
  828.     if (map[t]) {
  829.         for (n = side; n < (side + sides); n++) {
  830.         if (Floprd(ptr, 0L, drive, 1, t, n, st))
  831.             while (retry("Verify", t, n, start_dest) &&
  832.                Floprd(ptr, 0L, drive, 1, t, n, st));
  833.         abort_on_key(t,n);
  834.         }
  835.         Crawio((int) 'v');
  836.     }
  837.     }
  838. }
  839.  
  840. write_disk(drive, side)
  841. int             drive, side;
  842. {
  843.     char           *ptr;
  844.     int             t, n, last_track;
  845.  
  846.     ptr = buf;    
  847.     if(zero_disk){            /* formatting is a special case */
  848.     last_track = 2;
  849.     }else{
  850.     last_track = TRACK_MAP_SIZE;
  851.     }
  852.     for (t = 0; t < last_track; t++) {
  853.     if (track_map[t]) {
  854.         for (n = side; n < (side + sides); n++) {
  855.         if (Flopwr(ptr, 0L, drive, 1, t, n, st))
  856.             while (retry("Write", t, n, start_dest) &&
  857.                Flopwr(ptr, 0L, drive, 1, t, n, st));
  858.         ptr += (long) bps *st;
  859.  
  860.         abort_on_key(-1,n);
  861.         }
  862.         Crawio((int) '.');
  863.     }
  864.     }
  865. }
  866.  
  867. read_disk(drive, side)
  868. int             drive, side;
  869. {
  870.     char           *ptr = buf, c;
  871.     int             t, n;
  872.     int             full_track_retry;
  873.  
  874.     /* we need at least room for 1 track! */
  875.     if(buffer_size < (sides * bps * st * 1L)) longjmp(start, NO_MEMORY);
  876.     for (t = 0; t < TRACK_MAP_SIZE; t++) {
  877.     if (track_map[t]) {
  878.         c = ',';
  879.         for (n = side; n < (side + sides); n++) {
  880.         if (Floprd(ptr, 0L, drive, 1, t, n, st)) {
  881.             c = ';';
  882.             full_track_retry = 1;
  883.             while(1) {
  884.             abort_on_key(-1,n);
  885.             if (!Floprd(ptr, 0L, drive, 1, t, n, st))
  886.                 goto good_retry;
  887.             full_track_retry++;
  888.             if (full_track_retry >= TRACK_RETRY) {
  889.                 if (interactive && retry_track(t, n)) {
  890.                     full_track_retry = 1;
  891.                 }else{
  892.                     break;
  893.                 }
  894.             }
  895.             }
  896.             /* 4 retries done */
  897.             if (1 == sector_read(ptr, 0L, drive, 1, t, n, st)) {
  898.             if (interactive) {
  899.                 while (retry("Read", t, n, 0L) &&
  900.                 (1 == sector_read(ptr, 0L, drive, 1, t, n, st)));
  901.             }
  902.             }
  903.         }
  904.     good_retry:
  905.         ptr += (long) (bps * st);
  906.         abort_on_key(-1,n);
  907.         }
  908.         Crawio((int) c);
  909.     }
  910.     }
  911. }
  912.  
  913. input_track_map()
  914. {
  915.     char            text[10];
  916.     int             i, strack, etrack;
  917.  
  918.     if(play_it_again_sam) {
  919.     bcopy(full_track_map, track_map, TRACK_MAP_SIZE);
  920.     return;
  921.     }
  922.     for (i = 0; i < TRACK_MAP_SIZE; i++)
  923.     track_map[i] = '\0';
  924.     while ((printf("Enter start track (CR = done): "),
  925.         gets(text), (int) text[0])) {
  926.     strack = atoi(text) - 1;
  927.     printf("Enter end track (CR = %d): ", strack + 1);
  928.     gets(text);
  929.     if (!text[0])
  930.         etrack = strack;
  931.     else
  932.         etrack = atoi(text) - 1;
  933.     if ((etrack > TRACK_MAP_SIZE) ||
  934.         (strack > etrack) ||
  935.         (strack < 0)) {
  936.         printf("Sorry, not a valid entry: %d...%d\n",
  937.             strack + 1, etrack + 1);
  938.     } else {
  939.         for (i = strack; i <= etrack; i++)
  940.         track_map[i] = '\001';
  941.         printf("Ok, range %d...%d will be done\n",
  942.             strack + 1, etrack + 1);
  943.     }
  944.     }
  945. }
  946.  
  947. /*
  948.  * prompt_for_disk:
  949.  * ask user to insert disk if we think it is not in drive
  950.  */
  951.  
  952. prompt_for_disk(disk, drive, side)
  953. int disk, drive,side;
  954. {
  955.     if(drives_content[drive] != disk){
  956.     printf("\nInsert %s disk in drive %c (side %d),",
  957.         (disk == SOURCE_DISK ? "SOURCE" : "DESTINATION"),
  958.         (char)(drive + 'A'), side + 1);
  959.     printf("CR/SP = ok, other = abort\n");
  960.     if (!index("\r\n ", (char) Cnecin())){
  961.         if(disk == SOURCE_DISK)
  962.         one_valid_copy_done = 0;
  963.         longjmp(start, USER_ABORT);
  964.     }else{
  965.         drives_content[drive] = disk;
  966.     }
  967.     }
  968. }
  969.  
  970. /*
  971.  * update_checksum:
  972.  * compute checksum of boot buffer and set it (last int of 256 ints)
  973.  */
  974.  
  975. update_checksum(block, is_boot_non_executable)
  976. unsigned block[];
  977. unsigned is_boot_non_executable;
  978. {
  979.     int i; unsigned sum = 0;
  980.     for(i=0; i<255; i++)
  981.         sum += block[i];
  982.     block[255] = (unsigned) 0x1234 - sum + is_boot_non_executable;
  983. }
  984.  
  985. unsigned
  986. is_non_executable(block)
  987. unsigned block[];
  988. {
  989.     int i; unsigned sum = 0;
  990.     for(i=0; i<=255; i++)
  991.         sum += block[i];
  992.     return (sum == (unsigned) 0x1234 ? (unsigned) 0 : (unsigned) 1);
  993. }
  994.  
  995.