mformat.c

Go to the documentation of this file.
00001 /*
00002  * mformat.c
00003  */
00004 
00005 #define DONT_NEED_WAIT
00006 
00007 #include "sysincludes.h"
00008 #include "msdos.h"
00009 #include "mtools.h"
00010 #include "mainloop.h"
00011 #include "fsP.h"
00012 #include "file.h"
00013 #include "plain_io.h"
00014 #include "floppyd_io.h"
00015 #include "nameclash.h"
00016 #include "buffer.h"
00017 #ifdef USE_XDF
00018 #include "xdf_io.h"
00019 #endif
00020 #include "partition.h"
00021 
00022 #ifndef abs
00023 #define abs(x) ((x)>0?(x):-(x))
00024 #endif
00025 
00026 #ifdef OS_linux
00027 #include "linux/hdreg.h"
00028 
00029 #define _LINUX_STRING_H_
00030 #define kdev_t int
00031 #include "linux/fs.h"
00032 #undef _LINUX_STRING_H_
00033 
00034 #endif
00035 
00036 
00037 extern int errno;
00038 
00039 static int init_geometry_boot(struct bootsector *boot, struct device *dev,
00040                                int sectors0, int rate_0, int rate_any,
00041                                int *tot_sectors, int keepBoot)
00042 {
00043         int i;
00044         int nb_renum;
00045         int sector2;
00046         int size2;
00047         int j;
00048         int sum;
00049 
00050         set_word(boot->nsect, dev->sectors);
00051         set_word(boot->nheads, dev->heads);
00052 
00053         *tot_sectors = dev->heads * dev->sectors * dev->tracks - DWORD(nhs);
00054 
00055         if (*tot_sectors < 0x10000){
00056                 set_word(boot->psect, *tot_sectors);
00057                 set_dword(boot->bigsect, 0);
00058         } else {
00059                 set_word(boot->psect, 0);
00060                 set_dword(boot->bigsect, *tot_sectors);
00061         }
00062 
00063         if (dev->use_2m & 0x7f){
00064                 int bootOffset;
00065                 strncpy(boot->banner, "2M-STV04", 8);
00066                 boot->ext.old.res_2m = 0;
00067                 boot->ext.old.fmt_2mf = 6;
00068                 if ( dev->sectors % ( ((1 << dev->ssize) + 3) >> 2 ))
00069                         boot->ext.old.wt = 1;
00070                 else
00071                         boot->ext.old.wt = 0;
00072                 boot->ext.old.rate_0= rate_0;
00073                 boot->ext.old.rate_any= rate_any;
00074                 if (boot->ext.old.rate_any== 2 )
00075                         boot->ext.old.rate_any= 1;
00076                 i=76;
00077 
00078                 /* Infp0 */
00079                 set_word(boot->ext.old.Infp0, i);
00080                 boot->jump[i++] = sectors0;
00081                 boot->jump[i++] = 108;
00082                 for(j=1; j<= sectors0; j++)
00083                         boot->jump[i++] = j;
00084 
00085                 set_word(boot->ext.old.InfpX, i);
00086                 
00087                 boot->jump[i++] = 64;
00088                 boot->jump[i++] = 3;
00089                 nb_renum = i++;
00090                 sector2 = dev->sectors;
00091                 size2 = dev->ssize;
00092                 j=1;
00093                 while( sector2 ){
00094                         while ( sector2 < (1 << size2) >> 2 )
00095                                 size2--;
00096                         boot->jump[i++] = 128 + j;
00097                         boot->jump[i++] = j++;
00098                         boot->jump[i++] = size2;
00099                         sector2 -= (1 << size2) >> 2;
00100                 }
00101                 boot->jump[nb_renum] = ( i - nb_renum - 1 ) / 3;
00102 
00103                 set_word(boot->ext.old.InfTm, i);
00104 
00105                 sector2 = dev->sectors;
00106                 size2= dev->ssize;
00107                 while(sector2){
00108                         while ( sector2 < 1 << ( size2 - 2) )
00109                                 size2--;
00110                         boot->jump[i++] = size2;
00111                         sector2 -= 1 << (size2 - 2 );
00112                 }
00113                 
00114                 set_word(boot->ext.old.BootP,i);
00115                 bootOffset = i;
00116 
00117                 /* checksum */          
00118                 for (sum=0, j=64; j<i; j++) 
00119                         sum += boot->jump[j];/* checksum */
00120                 boot->ext.old.CheckSum=-sum;
00121                 return bootOffset;
00122         } else {
00123                 if(!keepBoot) {
00124                         boot->jump[0] = 0xeb;
00125                         boot->jump[1] = 0;
00126                         boot->jump[2] = 0x90;
00127                         strncpy(boot->banner, "MTOOL397", 8);
00128                         /* It looks like some versions of DOS are
00129                          * rather picky about this, and assume default
00130                          * parameters without this, ignoring any
00131                          * indication about cluster size et al. */
00132                 }
00133                 return 0;
00134         }
00135 }
00136 
00137 
00138 static int comp_fat_bits(Fs_t *Fs, int estimate, 
00139                          unsigned int tot_sectors, int fat32)
00140 {
00141         int needed_fat_bits;
00142 
00143         needed_fat_bits = 12;
00144 
00145 #define MAX_DISK_SIZE(bits,clusters) \
00146         TOTAL_DISK_SIZE((bits), Fs->sector_size, (clusters), \
00147                         Fs->num_fat, MAX_SECT_PER_CLUSTER)
00148 
00149         if(tot_sectors > MAX_DISK_SIZE(12, FAT12))
00150                 needed_fat_bits = 16;
00151         if(fat32 || tot_sectors > MAX_DISK_SIZE(16, FAT16))
00152                 needed_fat_bits = 32;
00153 
00154 #undef MAX_DISK_SIZE
00155 
00156         if(abs(estimate) && abs(estimate) < needed_fat_bits) {
00157                 if(fat32) {
00158                         fprintf(stderr,
00159                                 "Contradiction between FAT size on command line and FAT size in conf file\n");
00160                         exit(1);
00161                 }
00162                 fprintf(stderr,
00163                         "Device too big for a %d bit FAT\n",
00164                         estimate);
00165                 exit(1);
00166         }
00167 
00168         if(needed_fat_bits == 32 && !fat32 && abs(estimate) !=32){
00169                 fprintf(stderr,"Warning: Using 32 bit FAT.  Drive will only be accessibly by Win95 OEM / Win98\n");
00170         }
00171 
00172         if(!estimate) {
00173                 int min_fat16_size;
00174 
00175                 if(needed_fat_bits > 12)
00176                         return needed_fat_bits;
00177                 min_fat16_size = DISK_SIZE(16, Fs->sector_size, FAT12+1,
00178                                            Fs->num_fat, 1);
00179                 if(tot_sectors < min_fat16_size)
00180                         return 12;
00181                 else if(tot_sectors >= 2* min_fat16_size)
00182                         return 16; /* heuristics */
00183         }
00184 
00185         return estimate;
00186 }
00187 
00188 static void calc_fat_bits2(Fs_t *Fs, unsigned int tot_sectors, int fat_bits)
00189 {
00190         unsigned int rem_sect;
00191 
00192         /*
00193          * the "remaining sectors" after directory and boot
00194          * hasve been accounted for.
00195          */
00196         rem_sect = tot_sectors - Fs->dir_len - Fs->fat_start;
00197         switch(abs(fat_bits)) {
00198                 case 0:
00199 
00200 #define MY_DISK_SIZE(bits,clusters) \
00201                         DISK_SIZE( (bits), Fs->sector_size, (clusters), \
00202                                    Fs->num_fat, Fs->cluster_size)
00203 
00204                         if(rem_sect >= MY_DISK_SIZE(16, FAT12 + 1))
00205                                 /* big enough for FAT16 */
00206                                 set_fat16(Fs);
00207                         else if(rem_sect <= MY_DISK_SIZE(12, FAT12))
00208                                  /* small enough for FAT12 */
00209                                  set_fat12(Fs);
00210                         else {
00211                                 /* "between two chairs",
00212                                  * augment cluster size, and
00213                                  * settle it */
00214                                 if(Fs->cluster_size < MAX_SECT_PER_CLUSTER)
00215                                         Fs->cluster_size <<= 1;
00216                                 set_fat12(Fs);
00217                         }
00218                         break;
00219 #undef MY_DISK_SIZE
00220 
00221                 case 12:
00222                         set_fat12(Fs);
00223                         break;
00224                 case 16:
00225                         set_fat16(Fs);
00226                         break;
00227                 case 32:
00228                         set_fat32(Fs);
00229                         break;
00230         }
00231 }
00232 
00233 static inline void format_root(Fs_t *Fs, char *label, struct bootsector *boot)
00234 {
00235         Stream_t *RootDir;
00236         char *buf;
00237         int i;
00238         struct ClashHandling_t ch;
00239         int dirlen;
00240 
00241         init_clash_handling(&ch);
00242         ch.name_converter = label_name;
00243         ch.ignore_entry = -2;
00244 
00245         buf = safe_malloc(Fs->sector_size);
00246         RootDir = OpenRoot((Stream_t *)Fs);
00247         if(!RootDir){
00248                 fprintf(stderr,"Could not open root directory\n");
00249                 exit(1);
00250         }
00251 
00252         memset(buf, '\0', Fs->sector_size);
00253 
00254         if(Fs->fat_bits == 32) {
00255                 /* on a FAT32 system, we only write one sector,
00256                  * as the directory can be extended at will...*/
00257                 dirlen = 1;
00258                 fatAllocate(Fs, Fs->rootCluster, Fs->end_fat);
00259         } else
00260                 dirlen = Fs->dir_len; 
00261         for (i = 0; i < dirlen; i++)
00262                 WRITES(RootDir, buf, sectorsToBytes((Stream_t*)Fs, i),  
00263                            Fs->sector_size);
00264 
00265         ch.ignore_entry = 1;
00266         if(label[0])
00267                 mwrite_one(RootDir,label, 0, labelit, NULL,&ch);
00268 
00269         FREE(&RootDir);
00270         if(Fs->fat_bits == 32)
00271                 set_word(boot->dirents, 0);
00272         else
00273                 set_word(boot->dirents, Fs->dir_len * (Fs->sector_size / 32));
00274         free(buf);
00275 }
00276 
00277 
00278 static void xdf_calc_fat_size(Fs_t *Fs, unsigned int tot_sectors, int fat_bits)
00279 {
00280         unsigned int rem_sect;
00281 
00282         rem_sect = tot_sectors - Fs->dir_len - Fs->fat_start - 2 * Fs->fat_len;
00283 
00284         if(Fs->fat_len) {
00285                 /* an XDF disk, we know the fat_size and have to find
00286                  * out the rest. We start with a cluster size of 1 and
00287                  * keep doubling until everything fits into the
00288                  * FAT. This will occur eventually, as our FAT has a
00289                  * minimal size of 1 */
00290                 for(Fs->cluster_size = 1; 1 ; Fs->cluster_size <<= 1) {
00291                         Fs->num_clus = rem_sect / Fs->cluster_size;
00292                         if(abs(fat_bits) == 16 || Fs->num_clus > FAT12)
00293                                 set_fat16(Fs);
00294                         else
00295                                 set_fat12(Fs);
00296                         if (Fs->fat_len >= NEEDED_FAT_SIZE(Fs))
00297                                 return;
00298                 }
00299         }
00300         fprintf(stderr,"Internal error while calculating Xdf fat size\n");
00301         exit(1);
00302 }
00303 
00304 
00305 static void calc_fat_size(Fs_t *Fs, unsigned int tot_sectors)
00306 {
00307         unsigned int rem_sect;
00308         int tries;
00309         int occupied;
00310         
00311         tries=0;
00312         /* rough estimate of fat size */
00313         Fs->fat_len = 1;
00314         rem_sect = tot_sectors - Fs->dir_len - Fs->fat_start;
00315         while(1){
00316                 Fs->num_clus = (rem_sect - 2 * Fs->fat_len ) /Fs->cluster_size;
00317                 Fs->fat_len = NEEDED_FAT_SIZE(Fs);
00318                 occupied = 2 * Fs->fat_len + Fs->cluster_size * Fs->num_clus;
00319                 
00320                 /* if we have used up more than we have,
00321                  * we'll have to reloop */
00322                 
00323                 if ( occupied > rem_sect )
00324                         continue;
00325 
00326 
00327                 /* if we have exactly used up all
00328                  * sectors, fine */
00329                 if ( rem_sect - occupied < Fs->cluster_size )
00330                         break;
00331 
00332                 /* if we have not used up all our
00333                  * sectors, try again.  After the second
00334                  * try, decrease the amount of available
00335                  * space. This is to deal with the case of
00336                  * 344 or 345, ..., 1705, ... available
00337                  * sectors.  */
00338                 
00339                 switch(tries++){
00340                         default:
00341                                 /* this should never happen */
00342                                 fprintf(stderr,
00343                                         "Internal error in cluster/fat repartition"
00344                                         " calculation.\n");
00345                                 exit(1);
00346                         case 2:
00347                                 /* FALLTHROUGH */
00348                         case 1:
00349                                 rem_sect-= Fs->cluster_size;
00350                                 Fs->dir_len += Fs->cluster_size;
00351                         case 0:
00352                                 continue;
00353                 }
00354         }
00355 
00356         if ( Fs->num_clus > FAT12 && Fs->fat_bits == 12 ){
00357                 fprintf(stderr,"Too many clusters for this fat size."
00358                         " Please choose a 16-bit fat in your /etc/mtools"
00359                         " or .mtoolsrc file\n");
00360                 exit(1);
00361         }
00362         if ( Fs->num_clus <= FAT12 && Fs->fat_bits > 12 ){
00363                 fprintf(stderr,"Too few clusters for this fat size."
00364                         " Please choose a 12-bit fat in your /etc/mtools"
00365                         " or .mtoolsrc file\n");
00366                 exit(1);
00367         }
00368 }
00369 
00370 
00371 static unsigned char bootprog[]=
00372 {0xfa, 0x31, 0xc0, 0x8e, 0xd8, 0x8e, 0xc0, 0xfc, 0xb9, 0x00, 0x01,
00373  0xbe, 0x00, 0x7c, 0xbf, 0x00, 0x80, 0xf3, 0xa5, 0xea, 0x00, 0x00,
00374  0x00, 0x08, 0xb8, 0x01, 0x02, 0xbb, 0x00, 0x7c, 0xba, 0x80, 0x00,
00375  0xb9, 0x01, 0x00, 0xcd, 0x13, 0x72, 0x05, 0xea, 0x00, 0x7c, 0x00,
00376  0x00, 0xcd, 0x19};
00377 
00378 static inline void inst_boot_prg(struct bootsector *boot, int offset)
00379 {
00380         memcpy((char *) boot->jump + offset, 
00381                (char *) bootprog, sizeof(bootprog) /sizeof(bootprog[0]));
00382         boot->jump[0] = 0xeb;
00383         boot->jump[1] = offset - 1;
00384         boot->jump[2] = 0x90;
00385         set_word(boot->jump + offset + 20, offset + 24);
00386 }
00387 
00388 static void calc_cluster_size(struct Fs_t *Fs, unsigned int tot_sectors,
00389                               int fat_bits)
00390                               
00391 {
00392         unsigned int max_clusters; /* maximal possible number of sectors for
00393                                    * this FAT entry length (12/16/32) */
00394         unsigned int max_fat_size; /* maximal size of the FAT for this FAT
00395                                     * entry length (12/16/32) */
00396         unsigned int rem_sect; /* remaining sectors after we accounted for
00397                                 * the root directory and boot sector(s) */
00398 
00399         switch(abs(fat_bits)) {
00400                 case 12:                        
00401                         max_clusters = FAT12;
00402                         max_fat_size = Fs->num_fat * 
00403                                 FAT_SIZE(12, Fs->sector_size, max_clusters);
00404                         break;
00405                 case 16:
00406                 case 0: /* still hesititating between 12 and 16 */
00407                         max_clusters = FAT16;
00408                         max_fat_size = Fs->num_fat * 
00409                                 FAT_SIZE(16, Fs->sector_size, max_clusters);
00410                         break;
00411                 case 32:                  
00412                         Fs->cluster_size = 8;
00413                         /* According to
00414                          * http://www.microsoft.com/kb/articles/q154/9/97.htm,
00415                          * Micro$oft does not support FAT32 with less than 4K
00416                          */
00417                         return;
00418                 default:
00419                         fprintf(stderr,"Bad fat size\n");
00420                         exit(1);
00421         }
00422 
00423         rem_sect = tot_sectors - Fs->dir_len - Fs->fat_start;
00424 
00425         /* double the cluster size until we can fill up the disk with
00426          * the maximal number of sectors of this size */
00427         while(Fs->cluster_size * max_clusters  + max_fat_size < rem_sect) {
00428                 if(Fs->cluster_size > 64) {
00429                         /* bigger than 64. Should fit */
00430                         fprintf(stderr,
00431                                 "Internal error while calculating cluster size\n");
00432                         exit(1);
00433                 }
00434                 Fs->cluster_size <<= 1;
00435         }
00436 }
00437 
00438 
00439 struct OldDos_t old_dos[]={
00440 {   40,  9,  1, 4, 1, 2, 0xfc },
00441 {   40,  9,  2, 7, 2, 2, 0xfd },
00442 {   40,  8,  1, 4, 1, 1, 0xfe },
00443 {   40,  8,  2, 7, 2, 1, 0xff },
00444 {   80,  9,  2, 7, 2, 3, 0xf9 },
00445 {   80, 15,  2,14, 1, 7, 0xf9 },
00446 {   80, 18,  2,14, 1, 9, 0xf0 },
00447 {   80, 36,  2,15, 2, 9, 0xf0 },
00448 {    1,  8,  1, 1, 1, 1, 0xf0 },
00449 };
00450 
00451 static int old_dos_size_to_geom(int size, int *cyls, int *heads, int *sects)
00452 {
00453         int i;
00454         size = size * 2;
00455         for(i=0; i < sizeof(old_dos) / sizeof(old_dos[0]); i++){
00456                 if (old_dos[i].sectors * 
00457                     old_dos[i].tracks * 
00458                     old_dos[i].heads == size) {
00459                         *cyls = old_dos[i].tracks;
00460                         *heads = old_dos[i].heads;
00461                         *sects = old_dos[i].sectors;
00462                         return 0;
00463                 }
00464         }
00465         return 1;
00466 }
00467 
00468 
00469 static void calc_fs_parameters(struct device *dev, unsigned int tot_sectors,
00470                                struct Fs_t *Fs, struct bootsector *boot)
00471 {
00472         int i;
00473 
00474         for(i=0; i < sizeof(old_dos) / sizeof(old_dos[0]); i++){
00475                 if (dev->sectors == old_dos[i].sectors &&
00476                     dev->tracks == old_dos[i].tracks &&
00477                     dev->heads == old_dos[i].heads &&
00478                     (dev->fat_bits == 0 || abs(dev->fat_bits) == 12)){
00479                         boot->descr = old_dos[i].media;
00480                         Fs->cluster_size = old_dos[i].cluster_size;
00481                         Fs->dir_len = old_dos[i].dir_len;
00482                         Fs->fat_len = old_dos[i].fat_len;
00483                         Fs->fat_bits = 12;
00484                         break;
00485                 }
00486         }
00487         if (i == sizeof(old_dos) / sizeof(old_dos[0]) ){
00488                 /* a non-standard format */
00489                 if(DWORD(nhs))
00490                         boot->descr = 0xf8;
00491                   else
00492                         boot->descr = 0xf0;
00493 
00494 
00495                 if(!Fs->cluster_size) {
00496                         if (dev->heads == 1)
00497                                 Fs->cluster_size = 1;
00498                         else {
00499                                 Fs->cluster_size = (tot_sectors > 2000 ) ? 1:2;
00500                                 if (dev->use_2m & 0x7f)
00501                                         Fs->cluster_size = 1;
00502                         }
00503                 }
00504                 
00505                 if(!Fs->dir_len) {
00506                         if (dev->heads == 1)
00507                                 Fs->dir_len = 4;
00508                         else
00509                                 Fs->dir_len = (tot_sectors > 2000) ? 11 : 7;
00510                 }                       
00511 
00512                 calc_cluster_size(Fs, tot_sectors, dev->fat_bits);
00513                 if(Fs->fat_len)
00514                         xdf_calc_fat_size(Fs, tot_sectors, dev->fat_bits);
00515                 else {
00516                         calc_fat_bits2(Fs, tot_sectors, dev->fat_bits);
00517                         calc_fat_size(Fs, tot_sectors);
00518                 }
00519         }
00520 
00521         set_word(boot->fatlen, Fs->fat_len);
00522 }
00523 
00524 
00525 
00526 static void calc_fs_parameters_32(unsigned int tot_sectors,
00527                                   struct Fs_t *Fs, struct bootsector *boot)
00528 {
00529         if(DWORD(nhs))
00530                 boot->descr = 0xf8;
00531         else
00532                 boot->descr = 0xf0;
00533         if(!Fs->cluster_size)
00534                 /* According to
00535                  * http://www.microsoft.com/kb/articles/q154/9/97.htm,
00536                  * Micro$oft does not support FAT32 with less than 4K
00537                  */
00538                 Fs->cluster_size = 8;
00539         
00540         Fs->dir_len = 0;
00541         Fs->num_clus = tot_sectors / Fs->cluster_size;
00542         set_fat32(Fs);
00543         calc_fat_size(Fs, tot_sectors);
00544         set_word(boot->fatlen, 0);
00545         set_dword(boot->ext.fat32.bigFat, Fs->fat_len);
00546 }
00547 
00548 
00549 
00550 
00551 static void usage(void)
00552 {
00553         fprintf(stderr, 
00554                 "Mtools version %s, dated %s\n", mversion, mdate);
00555         fprintf(stderr, 
00556                 "Usage: %s [-t tracks] [-h heads] [-n sectors] "
00557                 "[-v label] [-1] [-4] [-8] [-f size] "
00558                 "[-N serialnumber] "
00559                 "[-k] [-B bootsector] [-r root_dir_len] [-L fat_len] "
00560                 "[-F] [-I fsVersion] [-C] [-c cluster_size] "
00561                 "[-H hidden_sectors] "
00562 #ifdef USE_XDF
00563                 "[-X] "
00564 #endif
00565                 "[-S hardsectorsize] [-M softsectorsize] [-3] "
00566                 "[-2 track0sectors] [-0 rate0] [-A rateany] [-a]"
00567                 "device\n", progname);
00568         exit(1);
00569 }
00570 
00571 void mformat(int argc, char **argv, int dummy)
00572 {
00573         int r; /* generic return value */
00574         Fs_t Fs;
00575         int hs, hs_set;
00576         int arguse_2m = 0;
00577         int sectors0=18; /* number of sectors on track 0 */
00578         int create = 0;
00579         int rate_0, rate_any;
00580         int mangled;
00581         int argssize=0; /* sector size */
00582         int msize=0;
00583         int fat32 = 0;
00584         struct label_blk_t *labelBlock;
00585         int bootOffset;
00586 
00587 #ifdef USE_XDF
00588         int i;
00589         int format_xdf = 0;
00590         struct xdf_info info;
00591 #endif
00592         struct bootsector *boot;
00593         char *bootSector=0;
00594         int c;
00595         int keepBoot = 0;
00596         struct device used_dev;
00597         int argtracks, argheads, argsectors;
00598         int tot_sectors;
00599         int blocksize;
00600 
00601         char *drive, name[EXPAND_BUF];
00602 
00603         char label[VBUFSIZE], buf[MAX_SECTOR], shortlabel[13];
00604         struct device *dev;
00605         char errmsg[200];
00606 
00607         unsigned long serial;
00608         int serial_set;
00609         int fsVersion;
00610 
00611         mt_off_t maxSize;
00612 
00613         int Atari = 0; /* should we add an Atari-style serial number ? */
00614 #ifdef OS_Minix
00615         char *devname;
00616         struct device onedevice[2];
00617         struct stat stbuf;
00618 #endif
00619  
00620         hs = hs_set = 0;
00621         argtracks = 0;
00622         argheads = 0;
00623         argsectors = 0;
00624         arguse_2m = 0;
00625         argssize = 0x2;
00626         label[0] = '\0';
00627         serial_set = 0;
00628         serial = 0;
00629         fsVersion = 0;
00630         
00631         Fs.cluster_size = 0;
00632         Fs.refs = 1;
00633         Fs.dir_len = 0;
00634         Fs.fat_len = 0;
00635         Fs.Class = &FsClass;    
00636         rate_0 = mtools_rate_0;
00637         rate_any = mtools_rate_any;
00638 
00639         /* get command line options */
00640         while ((c = getopt(argc,argv,
00641                            "148f:t:n:v:qub"
00642                            "kB:r:L:IFCc:Xh:s:l:N:H:M:S:230:Aa"))!= EOF) {
00643                 switch (c) {
00644                         /* standard DOS flags */
00645                         case '1':
00646                                 argheads = 1;
00647                                 break;
00648                         case '4':
00649                                 argsectors = 9;
00650                                 argtracks = 40;
00651                                 break;
00652                         case '8':
00653                                 argsectors = 8;
00654                                 argtracks = 40;
00655                                 break;
00656                         case 'f':
00657                                 r=old_dos_size_to_geom(atoi(optarg),
00658                                                        &argtracks, &argheads,
00659                                                        &argsectors);
00660                                 if(r) {
00661                                         fprintf(stderr, 
00662                                                 "Bad size %s\n", optarg);
00663                                         exit(1);
00664                                 }
00665                                 break;
00666                         case 't':
00667                                 argtracks = atoi(optarg);
00668                                 break;
00669 
00670                         case 'n': /*non-standard*/
00671                         case 's':
00672                                 argsectors = atoi(optarg);
00673                                 break;
00674 
00675                         case 'l': /* non-standard */
00676                         case 'v':
00677                                 strncpy(label, optarg, VBUFSIZE-1);
00678                                 label[VBUFSIZE-1] = '\0';
00679                                 break;
00680 
00681                         /* flags supported by Dos but not mtools */
00682                         case 'q':
00683                         case 'u':
00684                         case 'b':
00685                         /*case 's': leave this for compatibility */
00686                                 fprintf(stderr, 
00687                                         "Flag %c not supported by mtools\n",c);
00688                                 exit(1);
00689                                 
00690 
00691 
00692                         /* flags added by mtools */
00693                         case 'F':
00694                                 fat32 = 1;
00695                                 break;
00696 
00697 
00698                         case 'S':
00699                                 argssize = atoi(optarg) | 0x80;
00700                                 if(argssize < 0x81)
00701                                         usage();
00702                                 break;
00703 
00704 #ifdef USE_XDF
00705                         case 'X':
00706                                 format_xdf = 1;
00707                                 break;
00708 #endif
00709 
00710                         case '2':
00711                                 arguse_2m = 0xff;
00712                                 sectors0 = atoi(optarg);
00713                                 break;
00714                         case '3':
00715                                 arguse_2m = 0x80;
00716                                 break;
00717 
00718                         case '0': /* rate on track 0 */
00719                                 rate_0 = atoi(optarg);
00720                                 break;
00721                         case 'A': /* rate on other tracks */
00722                                 rate_any = atoi(optarg);
00723                                 break;
00724 
00725                         case 'M':
00726                                 msize = atoi(optarg);
00727                                 if (msize % 256 || msize > 8192 )
00728                                         usage();
00729                                 break;
00730 
00731                         case 'N':
00732                                 serial = strtoul(optarg,0,16);
00733                                 serial_set = 1;
00734                                 break;
00735                         case 'a': /* Atari style serial number */
00736                                 Atari = 1;
00737                                 break;
00738 
00739                         case 'C':
00740                                 create = O_CREAT;
00741                                 break;
00742 
00743                         case 'H':
00744                                 hs = atoi(optarg);
00745                                 hs_set = 1;
00746                                 break;
00747 
00748                         case 'I':
00749                                 fsVersion = strtoul(optarg,0,0);
00750                                 break;
00751 
00752                         case 'c':
00753                                 Fs.cluster_size = atoi(optarg);
00754                                 break;
00755 
00756                         case 'r': 
00757                                 Fs.dir_len = strtoul(optarg,0,0);
00758                                 break;
00759                         case 'L':
00760                                 Fs.fat_len = strtoul(optarg,0,0);
00761                                 break;
00762 
00763 
00764                         case 'B':
00765                                 bootSector = optarg;
00766                                 break;
00767                         case 'k':
00768                                 keepBoot = 1;
00769                                 break;
00770                         case 'h':
00771                                 argheads = atoi(optarg);
00772                                 break;
00773 
00774                         default:
00775                                 usage();
00776                 }
00777         }
00778 
00779         if (argc - optind != 1 ||
00780             skip_drive(argv[optind]) == argv[optind])
00781                 usage();
00782 
00783 #ifdef USE_XDF
00784         if(create && format_xdf) {
00785                 fprintf(stderr,"Create and XDF can't be used together\n");
00786                 exit(1);
00787         }
00788 #endif
00789         
00790         drive = get_drive(argv[argc -1], NULL);
00791 
00792 #ifdef OS_Minix
00793         devname = safe_malloc((9 + strlen(drive)) * sizeof(devname[0]));
00794         strcpy(devname, "/dev/dosX");
00795         if (isupper(drive[0]) && drive[1] == 0) {
00796                 /* single letter device name, use /dev/dos$drive */
00797                 devname[8]= drive[0];
00798         } else
00799         if (strchr(drive, '/') == NULL) {
00800                 /* a simple name, use /dev/$drive */
00801                 strcpy(devname+5, drive);
00802         } else {
00803                 /* a pathname, use as is. */
00804                 strcpy(devname, drive);
00805         }
00806         if (stat(devname, &stbuf) != -1) {
00807                 memset(onedevice, 0, sizeof(onedevice));
00808                 onedevice[0].name = devname;
00809                 onedevice[0].drive = drive;
00810                 onedevice[1].name = NULL;
00811                 onedevice[1].drive = NULL;
00812                 dev = onedevice;
00813         } else {
00814                 dev = devices;
00815         }
00816 #else
00817         dev = devices;
00818 #endif
00819 
00820         /* check out a drive whose letter and parameters match */       
00821         sprintf(errmsg, "Drive '%s:' not supported", drive);    
00822         Fs.Direct = NULL;
00823         blocksize = 0;
00824         for(;dev->drive;dev++) {
00825                 FREE(&(Fs.Direct));
00826                 /* drive name */
00827                 if (strcmp(dev->drive, drive) != 0)
00828                         continue;
00829                 used_dev = *dev;
00830 
00831                 SET_INT(used_dev.tracks, argtracks);
00832                 SET_INT(used_dev.heads, argheads);
00833                 SET_INT(used_dev.sectors, argsectors);
00834                 SET_INT(used_dev.use_2m, arguse_2m);
00835                 SET_INT(used_dev.ssize, argssize);
00836                 if(hs_set)
00837                         used_dev.hidden = hs;
00838                 
00839                 expand(dev->name, name);
00840 #ifdef USING_NEW_VOLD
00841                 strcpy(name, getVoldName(dev, name));
00842 #endif
00843 
00844 #ifdef USE_XDF
00845                 if(!format_xdf) {
00846 #endif
00847                         Fs.Direct = 0;
00848 #ifdef USE_FLOPPYD
00849                         Fs.Direct = FloppydOpen(&used_dev, dev, name, O_RDWR | create,
00850                                                                         errmsg, 0, 1);
00851                         if(Fs.Direct) {
00852                                 maxSize = max_off_t_31;
00853                         }
00854 #endif
00855                         if(!Fs.Direct) {                        
00856                                 Fs.Direct = SimpleFileOpen(&used_dev, dev, name,
00857                                                                                    O_RDWR | create,
00858                                                                                    errmsg, 0, 1, &maxSize);
00859                         }
00860 #ifdef USE_XDF
00861                 } else {
00862                         used_dev.misc_flags |= USE_XDF_FLAG;
00863                         Fs.Direct = XdfOpen(&used_dev, name, O_RDWR,
00864                                             errmsg, &info);
00865                         if(Fs.Direct && !Fs.fat_len)
00866                                 Fs.fat_len = info.FatSize;
00867                         if(Fs.Direct && !Fs.dir_len)
00868                                 Fs.dir_len = info.RootDirSize;
00869                 }
00870 #endif
00871 
00872                 if (!Fs.Direct)
00873                         continue;
00874 
00875 #ifdef OS_linux
00876                 if ((!used_dev.tracks || !used_dev.heads || !used_dev.sectors) &&
00877                         (!IS_SCSI(dev))) {
00878                         int fd= get_fd(Fs.Direct);
00879                         struct stat buf;
00880 
00881                         if (fstat(fd, &buf) < 0) {
00882                                 sprintf(errmsg, "Could not stat file (%s)", strerror(errno));
00883                                 continue;                                               
00884                         }
00885 
00886                         if (S_ISBLK(buf.st_mode)) {
00887                                 struct hd_geometry geom;
00888                                 long size;
00889                                 int sect_per_track;
00890 
00891                                 if (ioctl(fd, HDIO_GETGEO, &geom) < 0) {
00892                                         sprintf(errmsg, "Could not get geometry of device (%s)",
00893                                                         strerror(errno));
00894                                         continue;
00895                                 }
00896 
00897                                 if (ioctl(fd, BLKGETSIZE, &size) < 0) {
00898                                         sprintf(errmsg, "Could not get size of device (%s)",
00899                                                         strerror(errno));
00900                                         continue;
00901                                 }
00902 
00903                                 sect_per_track = geom.heads * geom.sectors;
00904                                 used_dev.heads = geom.heads;
00905                                 used_dev.sectors = geom.sectors;
00906                                 used_dev.hidden = geom.start % sect_per_track;
00907                                 used_dev.tracks = (size + used_dev.hidden) / sect_per_track;
00908                         }
00909                 }
00910 #endif
00911 
00912                 /* no way to find out geometry */
00913                 if (!used_dev.tracks || !used_dev.heads || !used_dev.sectors){
00914                         sprintf(errmsg, 
00915                                 "Unknown geometry "
00916                                 "(You must tell the complete geometry "
00917                                 "of the disk, \neither in /etc/mtools.conf or "
00918                                 "on the command line) ");
00919                         continue;
00920                 }
00921 
00922 #if 0
00923                 /* set parameters, if needed */
00924                 if(SET_GEOM(Fs.Direct, &used_dev, 0xf0, boot)){
00925                         sprintf(errmsg,"Can't set disk parameters: %s", 
00926                                 strerror(errno));
00927                         continue;
00928                 }
00929 #endif
00930                 Fs.sector_size = 512;
00931                 if( !(used_dev.use_2m & 0x7f)) {
00932                         Fs.sector_size = 128 << (used_dev.ssize & 0x7f);
00933                 }
00934 
00935                 SET_INT(Fs.sector_size, msize);
00936                 {
00937                     int i;
00938                     for(i = 0; i < 31; i++) {
00939                         if (Fs.sector_size == 1 << i) {
00940                             Fs.sectorShift = i;
00941                             break;
00942                         }
00943                     }
00944                     Fs.sectorMask = Fs.sector_size - 1;
00945                 }
00946 
00947                 if(!used_dev.blocksize || used_dev.blocksize < Fs.sector_size)
00948                         blocksize = Fs.sector_size;
00949                 else
00950                         blocksize = used_dev.blocksize;
00951                 
00952                 if(blocksize > MAX_SECTOR)
00953                         blocksize = MAX_SECTOR;
00954 
00955                 /* do a "test" read */
00956                 if (!create &&
00957                     READS(Fs.Direct, (char *) buf, 0, Fs.sector_size) != 
00958                     Fs.sector_size) {
00959                         sprintf(errmsg, 
00960                                 "Error reading from '%s', wrong parameters?",
00961                                 name);
00962                         continue;
00963                 }
00964                 break;
00965         }
00966 
00967 
00968         /* print error msg if needed */ 
00969         if ( dev->drive == 0 ){
00970                 FREE(&Fs.Direct);
00971                 fprintf(stderr,"%s: %s\n", argv[0],errmsg);
00972                 exit(1);
00973         }
00974 
00975         /* the boot sector */
00976         boot = (struct bootsector *) buf;
00977         if(bootSector) {
00978                 int fd;
00979 
00980                 fd = open(bootSector, O_RDONLY);
00981                 if(fd < 0) {
00982                         perror("open boot sector");
00983                         exit(1);
00984                 }
00985                 read(fd, buf, blocksize);
00986                 keepBoot = 1;
00987         }
00988         if(!keepBoot) {
00989                 memset((char *)boot, '\0', Fs.sector_size);
00990                 if(Fs.sector_size == 512 && !used_dev.partition) {
00991                         /* install fake partition table pointing to itself */
00992                         struct partition *partTable=(struct partition *)
00993                                 (((char*) boot) + 0x1ae);
00994                         setBeginEnd(&partTable[1], 0,
00995                                                 used_dev.heads * used_dev.sectors * used_dev.tracks,
00996                                                 used_dev.heads, used_dev.sectors, 1, 0);
00997                 }
00998         }
00999         set_dword(boot->nhs, used_dev.hidden);
01000 
01001         Fs.Next = buf_init(Fs.Direct,
01002                            blocksize * used_dev.heads * used_dev.sectors,
01003                            blocksize * used_dev.heads * used_dev.sectors,
01004                            blocksize);
01005         Fs.Buffer = 0;
01006 
01007         boot->nfat = Fs.num_fat = 2;
01008         if(!keepBoot)
01009                 set_word(boot->jump + 510, 0xaa55);
01010         
01011         /* get the parameters */
01012         tot_sectors = used_dev.tracks * used_dev.heads * used_dev.sectors - 
01013                 DWORD(nhs);
01014 
01015         set_word(boot->nsect, dev->sectors);
01016         set_word(boot->nheads, dev->heads);
01017 
01018         dev->fat_bits = comp_fat_bits(&Fs,dev->fat_bits, tot_sectors, fat32);
01019 
01020         if(dev->fat_bits == 32) {
01021                 Fs.primaryFat = 0;
01022                 Fs.writeAllFats = 1;
01023                 Fs.fat_start = 32;
01024                 calc_fs_parameters_32(tot_sectors, &Fs, boot);
01025 
01026                 Fs.clus_start = Fs.num_fat * Fs.fat_len + Fs.fat_start;
01027 
01028                 /* extension flags: mirror fats, and use #0 as primary */
01029                 set_word(boot->ext.fat32.extFlags,0);
01030 
01031                 /* fs version.  What should go here? */
01032                 set_word(boot->ext.fat32.fsVersion,fsVersion);
01033 
01034                 /* root directory */
01035                 set_dword(boot->ext.fat32.rootCluster, Fs.rootCluster = 2);
01036 
01037                 /* info sector */
01038                 set_word(boot->ext.fat32.infoSector, Fs.infoSectorLoc = 1);
01039                 Fs.infoSectorLoc = 1;
01040 
01041                 /* no backup boot sector */
01042                 set_word(boot->ext.fat32.backupBoot, 6);
01043                 
01044                 labelBlock = & boot->ext.fat32.labelBlock;
01045         } else {
01046                 Fs.infoSectorLoc = 0;
01047                 Fs.fat_start = 1;
01048                 calc_fs_parameters(&used_dev, tot_sectors, &Fs, boot);
01049                 Fs.dir_start = Fs.num_fat * Fs.fat_len + Fs.fat_start;
01050                 Fs.clus_start = Fs.dir_start + Fs.dir_len;
01051                 labelBlock = & boot->ext.old.labelBlock;
01052 
01053         }
01054         
01055         if (!keepBoot)
01056                 /* only zero out physdrive if we don't have a template
01057                  * bootsector */
01058                 labelBlock->physdrive = 0x00;
01059         labelBlock->reserved = 0;
01060         labelBlock->dos4 = 0x29;
01061 
01062         if (!serial_set || Atari)
01063                 srandom((long)time (0));
01064         if (!serial_set)
01065                 serial=random();
01066         set_dword(labelBlock->serial, serial);  
01067         if(!label[0])
01068                 strncpy(shortlabel, "NO NAME    ",11);
01069         else
01070                 label_name(label, 0, &mangled, shortlabel);
01071         strncpy(labelBlock->label, shortlabel, 11);
01072         sprintf(labelBlock->fat_type, "FAT%2.2d  ", Fs.fat_bits);
01073         labelBlock->fat_type[7] = ' ';
01074 
01075         set_word(boot->secsiz, Fs.sector_size);
01076         boot->clsiz = (unsigned char) Fs.cluster_size;
01077         set_word(boot->nrsvsect, Fs.fat_start);
01078 
01079         bootOffset = init_geometry_boot(boot, &used_dev, sectors0, 
01080                                         rate_0, rate_any,
01081                                         &tot_sectors, keepBoot);
01082         if(!bootOffset) {
01083                 bootOffset = ((char *) labelBlock) - ((char *) boot) +
01084                         sizeof(struct label_blk_t);
01085         }
01086         if(Atari) {
01087                 boot->banner[4] = 0;
01088                 boot->banner[5] = random();
01089                 boot->banner[6] = random();
01090                 boot->banner[7] = random();
01091         }               
01092 
01093         if (create) {
01094                 WRITES(Fs.Direct, (char *) buf,
01095                        sectorsToBytes((Stream_t*)&Fs, tot_sectors-1),
01096                        Fs.sector_size);
01097         }
01098 
01099         if(!keepBoot)
01100                 inst_boot_prg(boot, bootOffset);
01101         if(dev->use_2m & 0x7f)
01102                 Fs.num_fat = 1;
01103         Fs.lastFatSectorNr = 0;
01104         Fs.lastFatSectorData = 0;
01105         zero_fat(&Fs, boot->descr);
01106         Fs.freeSpace = Fs.num_clus;
01107         Fs.last = 2;
01108 
01109 #ifdef USE_XDF
01110         if(format_xdf)
01111                 for(i=0; 
01112                     i < (info.BadSectors+Fs.cluster_size-1)/Fs.cluster_size; 
01113                     i++)
01114                         fatEncode(&Fs, i+2, 0xfff7);
01115 #endif
01116 
01117         format_root(&Fs, label, boot);
01118         WRITES((Stream_t *)&Fs, (char *) boot, (mt_off_t) 0, Fs.sector_size);
01119         if(Fs.fat_bits == 32 && WORD(ext.fat32.backupBoot) != MAX32) {
01120                 WRITES((Stream_t *)&Fs, (char *) boot, 
01121                        sectorsToBytes((Stream_t*)&Fs, WORD(ext.fat32.backupBoot)),
01122                        Fs.sector_size);
01123         }
01124         FLUSH((Stream_t *)&Fs); /* flushes Fs. 
01125                                  * This triggers the writing of the FAT */
01126         FREE(&Fs.Next);
01127         Fs.Class->freeFunc((Stream_t *)&Fs);
01128 #ifdef USE_XDF
01129         if(format_xdf && isatty(0) && !getenv("MTOOLS_USE_XDF"))
01130                 fprintf(stderr,
01131                         "Note:\n"
01132                         "Remember to set the \"MTOOLS_USE_XDF\" environmental\n"
01133                         "variable before accessing this disk\n\n"
01134                         "Bourne shell syntax (sh, ash, bash, ksh, zsh etc):\n"
01135                         " export MTOOLS_USE_XDF=1\n\n"
01136                         "C shell syntax (csh and tcsh):\n"
01137                         " setenv MTOOLS_USE_XDF 1\n" ); 
01138 #endif
01139         exit(0);
01140 }

Generated on Fri Apr 14 22:56:56 2006 for minix by  doxygen 1.4.6