home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / diskutil / mtools / init.c < prev    next >
C/C++ Source or Header  |  1993-08-05  |  8KB  |  326 lines

  1. /*
  2.  * Initialize an MSDOS diskette.  Read the boot sector, and switch to the
  3.  * proper floppy disk device to match the format on the disk.  Sets a bunch
  4.  * of global variables.  Returns 0 on success, or 1 on failure.
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include <ctype.h>
  9. #include <sys/types.h>
  10. #include <sys/stat.h>
  11. #include "msdos.h"
  12.  
  13. #define FULL_CYL
  14. #define WORD(x) ((boot->x)[0] + ((boot->x)[1] << 8))
  15. #define DWORD(x) ((boot->x)[0] + ((boot->x)[1] << 8) + ((boot->x)[2] << 16) + ((boot->x)[3] << 24))
  16.  
  17. unsigned int num_clus;            /* total number of cluster */
  18. int num_fat;                /* the number of FAT tables */
  19. long disk_offset;            /* skip this many bytes */
  20. int fat_bits;                /* the FAT encoding scheme */
  21.  
  22. extern int fd, fat_len, dir_len, dir_start, clus_size, dir_dirty, disk_dirty;
  23. extern int fat_error, disk_size;
  24. extern long disk_current;
  25. extern char *mcwd;
  26. extern unsigned char *fat_buf, *disk_buf, *dir_buf;
  27. extern struct device devices[];
  28. static struct bootsector *read_boot();
  29.  
  30. int
  31. init(drive, mode)
  32. char drive;
  33. int mode;
  34. {
  35.     int fat_start, tracks, heads, sectors, old_dos;
  36.     char *malloc(), *name, *expand();
  37.     void perror(), exit(), reset_chain(), free(), fat_read();
  38.     struct bootsector *boot;
  39.     struct device *dev;
  40.  
  41.     if (fd != -1) {
  42.         close(fd);
  43.         free((char *) fat_buf);
  44.         free((char *) disk_buf);
  45.         free((char *) dir_buf);
  46.     }
  47.                     /* check out the drive letter */
  48.     dev = devices;
  49.     while (dev->drive) {
  50.         if (dev->drive == drive)
  51.             break;
  52.         dev++;
  53.     }
  54.     if (!dev->drive) {
  55.         fprintf(stderr, "Drive '%c:' not supported\n", drive);
  56.         return(1);
  57.     }
  58.                     /* open the device */
  59.     while (dev->name) {
  60.         if (dev->drive != drive)
  61.             break;
  62.  
  63.         name = expand(dev->name);
  64.         if ((fd = open(name, mode | dev->mode)) < 0) {
  65.             perror("init: open");
  66.             exit(1);
  67.         }
  68.                     /* set default parameters, if needed */
  69.         if (dev->gioctl) {
  70.             if ((*(dev->gioctl)) (fd, dev->tracks, dev->heads, dev->sectors))
  71.                 goto try_again;
  72.         }
  73.                     /* read the boot sector */
  74.         disk_offset = dev->offset;
  75.         if ((boot = read_boot()) == NULL)
  76.             goto try_again;
  77.  
  78.         heads = WORD(nheads);
  79.         sectors = WORD(nsect);
  80.         if (heads && sectors)
  81.             tracks = WORD(psect) / (unsigned) (heads * sectors);
  82.  
  83.                     /* sanity checking */
  84.         old_dos = 0;
  85.         if (!heads || heads > 100 || !sectors || sectors > 500 || tracks > 5000 || !boot->clsiz) {
  86.             /*
  87.              * The above technique will fail on diskettes that
  88.              * have been formatted with very old MSDOS, so we
  89.              * resort to the old table-driven method using the
  90.              * media signature (first byte in FAT).
  91.              */
  92.             unsigned char temp[MSECTOR_SIZE];
  93.             if (read(fd, (char *) temp, MSECTOR_SIZE) != MSECTOR_SIZE)
  94.                 temp[0] = '0';
  95.  
  96.             switch (temp[0]) {
  97.                 case 0xfe:    /* 160k */
  98.                     tracks = 40;
  99.                     sectors = 8;
  100.                     heads = 1;
  101.                     dir_start = 3;
  102.                     dir_len = 4;
  103.                     clus_size = 1;
  104.                     fat_len = 1;
  105.                     num_clus = 313;
  106.                     break;
  107.                 case 0xfc:    /* 180k */
  108.                     tracks = 40;
  109.                     sectors = 9;
  110.                     heads = 1;
  111.                     dir_start = 5;
  112.                     dir_len = 4;
  113.                     clus_size = 1;
  114.                     fat_len = 2;
  115.                     num_clus = 351;
  116.                     break;
  117.                 case 0xff:    /* 320k */
  118.                     tracks = 40;
  119.                     sectors = 8;
  120.                     heads = 2;
  121.                     dir_start = 3;
  122.                     dir_len = 7;
  123.                     clus_size = 2;
  124.                     fat_len = 1;
  125.                     num_clus = 315;
  126.                     break;
  127.                 case 0xfd:    /* 360k */
  128.                     tracks = 40;
  129.                     sectors = 9;
  130.                     heads = 2;
  131.                     dir_start = 5;
  132.                     dir_len = 7;
  133.                     clus_size = 2;
  134.                     fat_len = 2;
  135.                     num_clus = 354;
  136.                     break;
  137.                 default:
  138.                     fprintf(stderr, "Probable non-MSDOS disk\n");
  139.                     close(fd);
  140.                     fd = -1;
  141.                     return(1);
  142.             }
  143.             fat_start = 1;
  144.             num_fat = 2;
  145.             old_dos = 1;
  146.         }
  147.                     /* check the parameters */
  148.         if (dev->tracks && !dev->gioctl) {
  149.             if (dev->tracks == tracks && dev->heads == heads && dev->sectors == sectors)
  150.                 break;
  151.         }
  152.         else
  153.             break;
  154.  
  155. try_again:    close(fd);
  156.         fd = -1;
  157.         dev++;
  158.     }
  159.     if (fd == -1) {
  160.         if (boot != NULL && dev->tracks)
  161.             fprintf(stderr, "No support for %d tracks, %d heads, %d sector diskettes\n", tracks, heads, sectors);
  162.         return(1);
  163.     }
  164.                     /* set new parameters, if needed */
  165.     if (dev->gioctl) {
  166.         if ((*(dev->gioctl)) (fd, tracks, heads, sectors)) {
  167.             fprintf(stderr, "Can't set disk parameters\n");
  168.             close(fd);
  169.             fd = -1;
  170.             return(1);
  171.         }
  172.     }
  173.  
  174.     /*
  175.      * all numbers are in sectors, except num_clus (which is in clusters)
  176.      */
  177.     if (!old_dos) {
  178.         clus_size = boot->clsiz;
  179.         fat_start = WORD(nrsvsect);
  180.         fat_len = WORD(fatlen);
  181.         dir_start = fat_start + (boot->nfat * fat_len);
  182.         dir_len = WORD(dirents) * MDIR_SIZE / (unsigned) MSECTOR_SIZE;
  183.         /*
  184.          * For DOS partitions > 32M
  185.          */
  186.         if (WORD(psect) == 0)
  187.             num_clus = (unsigned int) (DWORD(bigsect) - dir_start - dir_len) / clus_size;
  188.         else
  189.             num_clus = (unsigned int) (WORD(psect) - dir_start - dir_len) / clus_size;
  190.         num_fat = boot->nfat;
  191.     }
  192.                     /* more sanity checking */
  193.     if (clus_size * MSECTOR_SIZE > MAX_CLUSTER) {
  194.         fprintf(stderr, "Cluster size of %d is larger than max of %d\n", clus_size * MSECTOR_SIZE, MAX_CLUSTER);
  195.         close(fd);
  196.         fd = -1;
  197.         return(1);
  198.     }
  199.     if (!old_dos && WORD(secsiz) != MSECTOR_SIZE) {
  200.         fprintf(stderr, "Sector size of %d is not supported\n", WORD(secsiz));
  201.         close(fd);
  202.         fd = -1;
  203.         return(1);
  204.     }
  205.                     /* full cylinder buffering */
  206. #ifdef FULL_CYL
  207.     disk_size = (dev->tracks) ? (sectors * heads) : 1;
  208. #else /* FULL_CYL */
  209.     disk_size = (dev->tracks) ? sectors : 1;
  210. #endif /* FULL_CYL */
  211.  
  212. /*
  213.  * The driver in Dell's SVR4 v2.01 is unreliable with large writes.
  214.  */
  215. #ifdef DELL
  216.     disk_size = 1;
  217. #endif /* DELL */
  218.  
  219.     disk_buf = (unsigned char *) malloc((unsigned int) disk_size * MSECTOR_SIZE);
  220.     if (disk_buf == NULL) {
  221.         perror("init: malloc");
  222.         exit(1);
  223.     }
  224.                     /* read the FAT sectors */
  225.     disk_current = -1000L;
  226.     disk_dirty = 0;
  227.     fat_error = 0;
  228.     fat_bits = dev->fat_bits;
  229.     fat_read(fat_start);
  230.                     /* set dir_chain[] to root directory */
  231.     dir_dirty = 0;
  232.     reset_chain(NEW);
  233.     return(0);
  234. }
  235.  
  236. /*
  237.  * Fix the info in the MCWD file to be a proper directory name.  Always
  238.  * has a leading separator.  Never has a trailing separator (unless it is
  239.  * the path itself).
  240.  */
  241.  
  242. char *
  243. fix_mcwd()
  244. {
  245.     FILE *fp;
  246.     struct stat sbuf;
  247.     char *s, *strcpy(), *strcat(), *mcwd_path, *getenv(), *strncpy();
  248.     char buf[BUFSIZ], *file, *expand();
  249.     static char ans[MAX_PATH];
  250.     long now, time();
  251.  
  252.     mcwd_path = getenv("MCWD");
  253.     if (mcwd_path == NULL || *mcwd_path == '\0')
  254.         mcwd_path = "$HOME/.mcwd";
  255.  
  256.     file = expand(mcwd_path);
  257.     if (stat(file, &sbuf) < 0)
  258.         return("A:/");
  259.     /*
  260.      * Ignore the info, if the file is more than 6 hours old
  261.      */
  262.     time(&now);
  263.     if (now - sbuf.st_mtime > 6 * 60 * 60) {
  264.         fprintf(stderr, "Warning: \"%s\" is out of date, contents ignored\n", file);
  265.         return("A:/");
  266.     }
  267.     
  268.     if (!(fp = fopen(file, "r")))
  269.         return("A:/");
  270.  
  271.     if (!fgets(buf, BUFSIZ, fp))
  272.         return("A:/");
  273.  
  274.     buf[strlen(buf) -1] = '\0';
  275.     fclose(fp);
  276.                     /* drive letter present? */
  277.     s = buf;
  278.     if (buf[0] && buf[1] == ':') {
  279.         strncpy(ans, buf, 2);
  280.         ans[2] = '\0';
  281.         s = &buf[2];
  282.     }
  283.     else 
  284.         strcpy(ans, "A:");
  285.                     /* add a leading separator */
  286.     if (*s != '/' && *s != '\\') {
  287.         strcat(ans, "/");
  288.         strcat(ans, s);
  289.     }
  290.     else
  291.         strcat(ans, s);
  292.                     /* translate to upper case */
  293.     for (s = ans; *s; ++s) {
  294.         if (islower(*s))
  295.             *s = toupper(*s);
  296.         if (*s == '\\')
  297.             *s = '/';
  298.     }
  299.                     /* if only drive, colon, & separator */
  300.     if (strlen(ans) == 3)
  301.         return(ans);
  302.                     /* zap the trailing separator */
  303.     if (*--s == '/')
  304.         *s = '\0';
  305.     return(ans);
  306. }
  307.  
  308. /*
  309.  * Read the boot sector.  We glean the disk parameters from this sector.
  310.  */
  311.  
  312. static struct bootsector *
  313. read_boot()
  314. {
  315.     long lseek();
  316.     static struct bootsector boot;
  317.  
  318.     if (lseek(fd, disk_offset, 0) < 0)
  319.         return(NULL);
  320.                     /* read the first sector */
  321.     if (read(fd, (char *) &boot, MSECTOR_SIZE) != MSECTOR_SIZE)
  322.         return(NULL);
  323.  
  324.     return(&boot);
  325. }
  326.