home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / disk-man / mtools-3.000 / mtools-3 / mtools-3.0 / mformat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-08  |  13.9 KB  |  611 lines

  1. /*
  2.  * mformat.c
  3.  */
  4.  
  5. #include "sysincludes.h"
  6. #include "msdos.h"
  7. #include "mtools.h"
  8. #include "streamcache.h"
  9. #include "fsP.h"
  10. #include "file.h"
  11. #include "plain_io.h"
  12. #include "nameclash.h"
  13. #include "buffer.h"
  14. #ifdef USE_XDF
  15. #include "xdf_io.h"
  16. #endif
  17.  
  18.  
  19. #include <math.h>
  20.  
  21. extern int errno;
  22.  
  23. static void init_geometry_boot(struct bootsector *boot, struct device *dev,
  24.                    int sectors0, int rate_0, int rate_any,
  25.                    int *tot_sectors)
  26. {
  27.     int i;
  28.     int nb_renum;
  29.     int sector2;
  30.     int size2;
  31.     int j;
  32.     int sum;
  33.  
  34.     set_word(boot->nsect, dev->sectors);
  35.     set_word(boot->nheads, dev->heads);
  36.  
  37.     *tot_sectors = dev->heads * dev->sectors * dev->tracks - DWORD(nhs);
  38.  
  39.     if (*tot_sectors < 0x10000){
  40.         set_word(boot->psect, *tot_sectors);
  41.         set_dword(boot->bigsect, 0);
  42.     } else {
  43.         set_word(boot->psect, 0);
  44.         set_dword(boot->bigsect, *tot_sectors);
  45.     }
  46.  
  47.     if (dev->use_2m & 0x7f){
  48.         strncpy(boot->banner, "2M-STV04", 8);
  49.         boot->res_2m = 0;
  50.         boot->fmt_2mf = 6;
  51.         if ( dev->sectors % ( ((1 << dev->ssize) + 3) >> 2 ))
  52.             boot->wt = 1;
  53.         else
  54.             boot->wt = 0;
  55.         boot->rate_0= rate_0;
  56.         boot->rate_any= rate_any;
  57.         if (boot->rate_any== 2 )
  58.             boot->rate_any= 1;
  59.         i=76;
  60.  
  61.         /* Infp0 */
  62.         set_word(boot->Infp0, i);
  63.         boot->jump[i++] = sectors0;
  64.         boot->jump[i++] = 108;
  65.         for(j=1; j<= sectors0; j++)
  66.             boot->jump[i++] = j;
  67.  
  68.         set_word(boot->InfpX, i);
  69.         
  70.         boot->jump[i++] = 64;
  71.         boot->jump[i++] = 3;
  72.         nb_renum = i++;
  73.         sector2 = dev->sectors;
  74.         size2 = dev->ssize;
  75.         j=1;
  76.         while( sector2 ){
  77.             while ( sector2 < (1 << size2) >> 2 )
  78.                 size2--;
  79.             boot->jump[i++] = 128 + j;
  80.             boot->jump[i++] = j++;
  81.             boot->jump[i++] = size2;
  82.             sector2 -= (1 << size2) >> 2;
  83.         }
  84.         boot->jump[nb_renum] = ( i - nb_renum - 1 ) / 3;
  85.  
  86.         set_word(boot->InfTm, i);
  87.  
  88.         sector2 = dev->sectors;
  89.         size2= dev->ssize;
  90.         while(sector2){
  91.             while ( sector2 < 1 << ( size2 - 2) )
  92.                 size2--;
  93.             boot->jump[i++] = size2;
  94.             sector2 -= 1 << (size2 - 2 );
  95.         }
  96.         
  97.         set_word(boot->BootP,i);
  98.  
  99.         /* checksum */        
  100.         for (sum=0, j=64; j<i; j++) 
  101.             sum += boot->jump[j];/* checksum */
  102.         boot->CheckSum=-sum;
  103.     } else {
  104.         strncpy(boot->banner, "MTOOLS  ", 8);
  105.         set_word(boot->BootP, OFFSET(BootP) + 2);
  106.     }
  107.     return;
  108. }
  109.  
  110.  
  111. static int comp_fat_bits(struct Fs_t *Fs, int fat_bits)
  112. {
  113.     if (fat_bits == 0 ){
  114.         if (Fs->num_clus >= FAT12)
  115.             Fs->fat_bits = 16;
  116.         else
  117.             Fs->fat_bits = 12;
  118.     } else if (fat_bits < 0) 
  119.         Fs->fat_bits = -fat_bits;
  120.     else
  121.         Fs->fat_bits = fat_bits;
  122.     return Fs->fat_bits;
  123. }
  124.  
  125.  
  126. static inline void format_fat(Fs_t *Fs, struct bootsector *boot)
  127. {
  128.     int buflen;
  129.     
  130.     Fs->fat_error = 0;
  131.  
  132.     buflen = Fs->fat_len * Fs->sector_size;
  133.     Fs->fat_buf = safe_malloc(buflen);
  134.  
  135.     memset((char *) Fs->fat_buf, '\0', Fs->sector_size * Fs->fat_len);
  136.     Fs->fat_buf[0] = boot->descr;
  137.     Fs->fat_buf[1] = 0xff;
  138.     Fs->fat_buf[2] = 0xff;
  139.     Fs->fat_dirty = 1;
  140.     if ( Fs->fat_bits == 16 )
  141.         Fs->fat_buf[3] = 0xff;
  142. }
  143.  
  144.  
  145. static inline void format_root(Fs_t *Fs, char *label, struct bootsector *boot)
  146. {
  147.     Stream_t *RootDir;
  148.     char *buf;
  149.     int i;
  150.     struct ClashHandling_t ch;
  151.  
  152.     init_clash_handling(&ch);
  153.     ch.name_converter = label_name;
  154.     ch.ignore_entry = -2;
  155.  
  156.     buf = safe_malloc(Fs->sector_size);
  157.     RootDir = open_root(COPY((Stream_t *)Fs));
  158.     if(!RootDir){
  159.         fprintf(stderr,"Could not open root directory\n");
  160.         cleanup_and_exit(1);
  161.     }
  162.  
  163.     memset(buf, '\0', Fs->sector_size);
  164.     WRITES(RootDir, buf, 0, Fs->sector_size);
  165.     for (i = 1; i < Fs->dir_len; i++)
  166.         WRITES(RootDir, buf, i * Fs->sector_size, Fs->sector_size);
  167.  
  168.     ch.ignore_entry = 1;
  169.     if(label[0])
  170.         mwrite_one(RootDir,(Stream_t *) Fs,
  171.                "mformat",label, 0, labelit, NULL,&ch);
  172.  
  173.     FREE(&RootDir);
  174.     set_word(boot->dirents, Fs->dir_len * 16);
  175. }
  176.  
  177. static void calc_fat_size(Fs_t *Fs, int tot_sectors, int fat_bits)
  178. {
  179.     int rem_sect;
  180.     int tries;
  181.     int occupied;
  182.     
  183.     /* the "remaining sectors" after directory and boot
  184.      * has been accounted for.
  185.      */
  186.     rem_sect = tot_sectors - Fs->dir_len - 1;
  187.     
  188.     /* rough estimate of fat size */
  189.     Fs->fat_len = 1;    
  190.     tries=0;
  191.     
  192.     while(1){
  193.         Fs->num_clus = (rem_sect - 2 * Fs->fat_len ) /Fs->cluster_size;
  194.         comp_fat_bits(Fs, fat_bits);
  195.         Fs->fat_len = NEEDED_FAT_SIZE(Fs);
  196.         occupied = 2 * Fs->fat_len + Fs->cluster_size * Fs->num_clus;
  197.         
  198.         /* if we have exactly used up all
  199.          * sectors, fine */
  200.         if ( occupied == rem_sect )
  201.             break;
  202.         
  203.         /* if we have used up more than we have,
  204.          * we'll have to reloop */
  205.         
  206.         if ( occupied > rem_sect )
  207.             continue;
  208.         
  209.         /* if we have not used up all our
  210.          * sectors, try again.  After the second
  211.          * try, decrease the amount of available
  212.          * space. This is to deal with the case of
  213.          * 344 or 345, ..., 1705, ... available
  214.          * sectors.  */
  215.         
  216.         switch(tries++){
  217.         default:
  218.             /* this should never happen */
  219.             fprintf(stderr,
  220.                 "Internal error in cluster/fat repartition"
  221.                 " calculation.\n");
  222.                 cleanup_and_exit(1);
  223.         case 2:
  224.             /* FALLTHROUGH */
  225.         case 1:
  226.             rem_sect--;
  227.         case 0:
  228.             continue;
  229.         }
  230.     }
  231.  
  232.     if ( Fs->num_clus >= FAT12 && Fs->fat_bits == 12 ){
  233.         fprintf(stderr,"Too many clusters for this fat size."
  234.             " Please choose a 16-bit fat in your /etc/mtools"
  235.             " or .mtoolsrc file\n");
  236.         cleanup_and_exit(1);
  237.     }
  238. }
  239.  
  240.  
  241. static unsigned char bootprog[]=
  242. {0xfa, 0x31, 0xc0, 0x8e, 0xd8, 0x8e, 0xc0, 0xfc, 0xb9, 0x00, 0x01,
  243.  0xbe, 0x00, 0x7c, 0xbf, 0x00, 0x80, 0xf3, 0xa5, 0xea, 0x00, 0x00,
  244.  0x00, 0x08, 0xb8, 0x01, 0x02, 0xbb, 0x00, 0x7c, 0xba, 0x80, 0x00,
  245.  0xb9, 0x01, 0x00, 0xcd, 0x13, 0x72, 0x05, 0xea, 0x00, 0x7c, 0x00,
  246.  0x00, 0xcd, 0x19};
  247.  
  248. static inline void inst_boot_prg(struct bootsector *boot)
  249. {
  250.     int offset = WORD(BootP);
  251.     memcpy((char *) boot->jump + offset, 
  252.            (char *) bootprog, sizeof(bootprog) /sizeof(bootprog[0]));
  253.     boot->jump[0] = 0xe9;
  254.     boot->jump[1] = offset + 1;
  255.     boot->jump[2] = 0x90;
  256.     set_word(boot->jump + offset + 20, offset + 24);
  257. }
  258.  
  259. struct OldDos_t old_dos[]={
  260. {   40,  9,  1, 4, 1, 2, 0xfc },
  261. {   40,  9,  2, 7, 2, 2, 0xfd },
  262. {   40,  8,  1, 4, 1, 1, 0xfe },
  263. {   40,  8,  2, 7, 2, 1, 0xff },
  264. {   80,  9,  2, 7, 2, 3, 0xf9 },
  265. {   80, 15,  2,14, 1, 7, 0xf9 },
  266. {   80, 18,  2,14, 1, 9, 0xf0 },
  267. {   80, 36,  2,15, 2, 9, 0xf0 }
  268. };
  269.  
  270. static void calc_fs_parameters(struct device *dev,
  271.                    struct Fs_t *Fs, struct bootsector *boot)
  272. {
  273.  
  274.     int tot_sectors;
  275.     int i;
  276.  
  277.     /* get the parameters */
  278.     tot_sectors = dev->tracks * dev->heads * dev->sectors - DWORD(nhs);
  279.     for(i=0; i < sizeof(old_dos) / sizeof(old_dos[0]); i++){
  280.         if (dev->sectors == old_dos[i].sectors &&
  281.             dev->tracks == old_dos[i].tracks &&
  282.             dev->heads == old_dos[i].heads &&
  283.             (dev->fat_bits == 0 || dev->fat_bits == 12 || 
  284.              dev->fat_bits == -12)){
  285.             boot->descr = old_dos[i].media;
  286.             Fs->cluster_size = old_dos[i].cluster_size;
  287.             Fs->dir_len = old_dos[i].dir_len;
  288.             Fs->fat_len = old_dos[i].fat_len;
  289.             Fs->fat_bits = 12;
  290.             break;
  291.         }
  292.     }
  293.     if (i == sizeof(old_dos) / sizeof(old_dos[0]) ){
  294.         /* a non-standard format */
  295.         if(DWORD(nhs))
  296.             boot->descr = 0xf8;
  297.         else
  298.             boot->descr = 0xf0;
  299.         if (dev->heads == 1)
  300.             Fs->cluster_size = 1;
  301.         else {
  302.             Fs->cluster_size = (tot_sectors > 2000 ) ? 1 : 2;
  303.             if (dev->use_2m & 0x7f)
  304.                 Fs->cluster_size = 1;
  305.         }
  306.  
  307.         if (dev->heads == 1)
  308.             Fs->dir_len = 4;
  309.         else
  310.             Fs->dir_len = (tot_sectors > 2000) ? 10 : 7;
  311.  
  312.         Fs->num_clus = tot_sectors / Fs->cluster_size;
  313.         while (comp_fat_bits(Fs, dev->fat_bits) == 12 && 
  314.                !(dev->use_2m & 0x7f) && Fs->num_clus >= FAT12){
  315.             Fs->cluster_size <<= 1;
  316.             Fs->num_clus = tot_sectors / Fs->cluster_size;
  317.         }
  318.         
  319.         if ( (Fs->dir_len * 512 ) % Fs->sector_size ){
  320.             Fs->dir_len += Fs->sector_size / 512;
  321.             Fs->dir_len -= Fs->dir_len % (Fs->sector_size / 512);
  322.         }
  323.  
  324.         calc_fat_size(Fs, tot_sectors, dev->fat_bits);
  325.     }
  326.  
  327.     set_word(boot->secsiz, Fs->sector_size);
  328.     boot->clsiz = (unsigned char) Fs->cluster_size;
  329.  
  330.     set_word(boot->fatlen, Fs->fat_len);
  331.     set_word(boot->nsect, dev->sectors);
  332.     set_word(boot->nheads, dev->heads);
  333. }
  334.  
  335.  
  336.  
  337. void mformat(int argc, char **argv, int dummy)
  338. {
  339.     Fs_t Fs;
  340.     int hs;
  341.     int arguse_2m = 0;
  342.     int sectors0=18; /* number of sectors on track 0 */
  343.     int create = 0;
  344.     int rate_0, rate_any;
  345.     int mangled;
  346.     int argssize=0; /* sector size */
  347.     int msize=0;
  348. #ifdef USE_XDF
  349.     int format_xdf = 0;
  350. #endif
  351.     struct bootsector *boot;
  352.     int c, oops;
  353.     struct device used_dev;
  354.     int argtracks, argheads, argsectors;
  355.     int tot_sectors;
  356.  
  357.     char drive, name[EXPAND_BUF];
  358.  
  359.     char label[VBUFSIZE], buf[MAX_SECTOR], shortlabel[13];
  360.     struct device *dev;
  361.     char errmsg[80];
  362.  
  363.     unsigned long serial;
  364.      int serial_set;
  365.  
  366.     int Atari = 0; /* should we add an Atari-style serial number ? */
  367.  
  368.     hs = 0;
  369.     oops = 0;
  370.     argtracks = 0;
  371.     argheads = 0;
  372.     argsectors = 0;
  373.     arguse_2m = 0;
  374.     argssize = 0x2;
  375.     label[0] = '\0';
  376.     serial_set = 0;
  377.     serial = 0;
  378.  
  379.     Fs.refs = 1;
  380.     Fs.Class = &FsClass;
  381.     rate_0 = mtools_rate_0;
  382.     rate_any = mtools_rate_any;
  383.  
  384.     /* get command line options */
  385.     while ((c = getopt(argc, argv, "CXt:h:s:l:n:H:M:S:12:0Aa")) != EOF) {
  386.         switch (c) {
  387.             case 'C':
  388.                 create = O_CREAT;
  389.                 break;
  390.             case 'H':
  391.                 hs = atoi(optarg);
  392.                 break;
  393. #ifdef USE_XDF
  394.             case 'X':
  395.                 format_xdf = 1;
  396.                 break;
  397. #endif
  398.             case 't':
  399.                 argtracks = atoi(optarg);
  400.                 break;
  401.             case 'h':
  402.                 argheads = atoi(optarg);
  403.                 break;
  404.             case 's':
  405.                 argsectors = atoi(optarg);
  406.                 break;
  407.             case 'l':
  408.                 strncpy(label, optarg, VBUFSIZE-1);
  409.                 label[VBUFSIZE-1] = '\0';
  410.                 break;
  411.              case 'n':
  412.                  serial = strtoul(optarg,0,0);
  413.                  serial_set = 1;
  414.                  break;
  415.             case 'S':
  416.                 argssize = atoi(optarg) | 0x80;
  417.                 if(argssize < 0x81)
  418.                     oops = 1;
  419.                 break;
  420.             case 'M':
  421.                 msize = atoi(optarg);
  422.                 if (msize % 256 || msize > 8192 )
  423.                     oops=1;                    
  424.                 break;
  425.             case '1':
  426.                 arguse_2m = 0x80;
  427.                 break;
  428.             case '2':
  429.                 arguse_2m = 0xff;
  430.                 sectors0 = atoi(optarg);
  431.                 break;
  432.             case '0': /* rate on track 0 */
  433.                 rate_0 = atoi(optarg);
  434.                 break;
  435.             case 'A': /* rate on other tracks */
  436.                 rate_any = atoi(optarg);
  437.                 break;
  438.             case 'a': /* Atari style serial number */
  439.                 Atari = 1;
  440.                 break;
  441.             default:
  442.                 oops = 1;
  443.                 break;
  444.         }
  445.     }
  446.  
  447.     if (oops || (argc - optind) != 1 ||
  448.         !argv[optind][0] || argv[optind][1] != ':') {
  449.         fprintf(stderr, 
  450.             "Mtools version %s, dated %s\n", mversion, mdate);
  451.         fprintf(stderr, 
  452.             "Usage: %s [-V] [-t tracks] [-h heads] [-s sectors] "
  453.             "[-l label] [-n serialnumber] "
  454.             "[-S hardsectorsize] [-M softsectorsize] [-1]"
  455.             "[-2 track0sectors] [-0 rate0] [-A rateany] [-a]"
  456.             "device\n", argv[0]);
  457.         cleanup_and_exit(1);
  458.     }
  459.  
  460. #ifdef USE_XDF
  461.     if(create && format_xdf) {
  462.         fprintf(stderr,"Create and XDF can't be used together\n");
  463.         cleanup_and_exit(1);
  464.     }
  465. #endif
  466.     
  467.     drive = toupper(argv[argc -1][0]);
  468.  
  469.     /* check out a drive whose letter and parameters match */    
  470.     sprintf(errmsg, "Drive '%c:' not supported", drive);    
  471.     Fs.Direct = NULL;
  472.     for(dev=devices;dev->drive;dev++) {
  473.         FREE(&(Fs.Direct));
  474.         /* drive letter */
  475.         if (dev->drive != drive)
  476.             continue;
  477.         used_dev = *dev;
  478.  
  479.         set_uint(&used_dev.tracks, argtracks);
  480.         set_uint(&used_dev.heads, argheads);
  481.         set_uint(&used_dev.sectors, argsectors);
  482.         set_uint(&used_dev.use_2m, arguse_2m);
  483.         set_uint(&used_dev.ssize, argssize);
  484.         
  485.         expand(dev->name, name);
  486. #ifdef USE_XDF
  487.         if(!format_xdf)
  488. #endif
  489.             Fs.Direct = SimpleFloppyOpen(&used_dev, dev, name,
  490.                              O_RDWR | create,
  491.                              errmsg);
  492. #ifdef USE_XDF
  493.         else
  494.             Fs.Direct = Fs.Direct = XdfOpen(&used_dev, name, O_RDWR,
  495.                             errmsg);
  496. #endif
  497.  
  498.         if (!Fs.Direct) {
  499.             sprintf(errmsg,"init: open: %s", strerror(errno));
  500.             continue;
  501.         }            
  502.  
  503.         /* non removable media */
  504.         if (!used_dev.tracks || !used_dev.heads || !used_dev.sectors){
  505.             sprintf(errmsg, 
  506.                 "Non-removable media is not supported "
  507.                 "(You must tell the complete geometry "
  508.                 "of the disk, either in /etc/mtools or "
  509.                 "on the command line) ");
  510.             continue;
  511.         }
  512.  
  513. #if 0
  514.         /* set parameters, if needed */
  515.         if(SET_GEOM(Fs.Direct, &used_dev, 0xf0, boot)){
  516.             sprintf(errmsg,"Can't set disk parameters: %s", 
  517.                 strerror(errno));
  518.             continue;
  519.         }
  520. #endif
  521.         Fs.sector_size = 512;
  522.         if( !(used_dev.use_2m & 0x7f))
  523.             Fs.sector_size = 128 << (used_dev.ssize & 0x7f);
  524.         set_uint(&Fs.sector_size, msize);
  525.  
  526.         /* do a "test" read */
  527.         if (!create &&
  528.             READS(Fs.Direct, (char *) buf, 0, Fs.sector_size) != 
  529.             Fs.sector_size) {
  530.             sprintf(errmsg, 
  531.                 "Error reading from '%s', wrong parameters?",
  532.                 name);
  533.             continue;
  534.         }
  535.         break;
  536.     }
  537.  
  538.  
  539.     /* print error msg if needed */    
  540.     if ( dev->drive == 0 ){
  541.         FREE(&Fs.Direct);
  542.         fprintf(stderr,"%s: %s\n", argv[0],errmsg);
  543.         cleanup_and_exit(1);
  544.     }
  545.  
  546.     /* the boot sector */
  547.     boot = (struct bootsector *) buf;
  548.     memset((char *)boot, '\0', Fs.sector_size);
  549.     set_dword(boot->nhs, hs);
  550.  
  551.     Fs.Next = buf_init(Fs.Direct,
  552.                Fs.sector_size * used_dev.heads * used_dev.sectors,
  553.                Fs.sector_size,
  554.                Fs.sector_size * used_dev.heads * used_dev.sectors);
  555.     calc_fs_parameters(&used_dev, &Fs, boot);
  556.  
  557.     set_word(boot->nrsvsect, Fs.fat_start = 1);
  558.     boot->nfat = Fs.num_fat = 2;
  559.     boot->physdrive = 0;
  560.     boot->reserved = 0;
  561.     boot->dos4 = 0x29;
  562.     Fs.dir_start = Fs.num_fat * Fs.fat_len + Fs.fat_start;
  563.     set_word(boot->jump + 510, 0xaa55);
  564.       if (!serial_set || Atari)
  565.         srandom(time (0));
  566.       if (!serial_set)
  567.         serial=random();
  568.      set_dword(boot->serial, serial);    
  569.     if(!label[0])
  570.         strncpy(shortlabel, "NO NAME    ",11);
  571.     else
  572.         label_name(label, 0, &mangled, shortlabel);
  573.     strncpy(boot->label, shortlabel, 11);
  574.     sprintf(boot->fat_type, "FAT%2.2d   ", Fs.fat_bits);
  575.     init_geometry_boot(boot, &used_dev, sectors0, rate_0, rate_any,
  576.                &tot_sectors);
  577.     if(Atari) {
  578.         boot->banner[4] = 0;
  579.         boot->banner[5] = random();
  580.         boot->banner[6] = random();
  581.         boot->banner[7] = random();
  582.     }        
  583.  
  584.     if (create) {
  585.         WRITES(Fs.Direct, (char *) buf,
  586.                Fs.sector_size * (tot_sectors-1),
  587.                Fs.sector_size);
  588.     }
  589.  
  590.     inst_boot_prg(boot);
  591.     if(dev->use_2m & 0x7f)
  592.         Fs.num_fat = 1;
  593.     format_fat(&Fs, boot);
  594.     format_root(&Fs, label, boot);
  595.     WRITES((Stream_t *)&Fs, (char *) boot, 0, Fs.sector_size);    
  596.     FLUSH((Stream_t *)&Fs); /* flushes Fs. 
  597.                  * This triggers the writing of the fats */
  598. #ifdef USE_XDF
  599.     if(format_xdf && isatty(0) && !getenv("MTOOLS_USE_XDF"))
  600.         fprintf(stderr,
  601.             "Note:\n"
  602.             "Remember to set the \"MTOOLS_USE_XDF\" environmental\n"
  603.             "variable before accessing this disk\n\n"
  604.             "Bourne shell syntax (sh, ash, bash, ksh, zsh etc):\n"
  605.             " export MTOOLS_USE_XDF=1\n\n"
  606.             "C shell syntax (csh and tcsh):\n"
  607.             " setenv MTOOLS_USE_XDF 1\n" );    
  608. #endif
  609.     cleanup_and_exit(0);
  610. }
  611.