home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / CMDS / mtools_3.6.src.lzh / MTOOLS_3.6 / fat.c < prev    next >
C/C++ Source or Header  |  1997-11-12  |  18KB  |  828 lines

  1. #include "sysincludes.h"
  2. #include "msdos.h"
  3. #include "stream.h"
  4. #include "mtools.h"
  5. #include "fsP.h"
  6.  
  7. extern Stream_t *default_drive;
  8.  
  9.  
  10. #define SECT_PER_ENTRY (sizeof(int)*8)
  11.  
  12. static FatMap_t *GetFatMap(Fs_t *Stream)
  13. {
  14.     int nr_entries,i;
  15.     FatMap_t *map;
  16.  
  17.     Stream->fat_error = 0;
  18.     nr_entries = (Stream->fat_len + SECT_PER_ENTRY - 1) / SECT_PER_ENTRY;
  19.     map = NewArray(nr_entries, FatMap_t);
  20.     if(!map)
  21.         return 0;
  22.  
  23.     for(i=0; i< nr_entries; i++) {
  24.         map[i].data = 0;
  25.         map[i].valid = 0;
  26.         map[i].dirty = 0;
  27.     }
  28.  
  29.     return map;
  30. }
  31.  
  32. static int locate(Fs_t *Stream, int offset, int *slot, int *bit)
  33. {
  34.     if(offset > Stream->fat_len)
  35.         return -1;
  36.     *slot = offset / SECT_PER_ENTRY;
  37.     *bit = offset % SECT_PER_ENTRY;
  38.     return 0;
  39. }
  40.  
  41.  
  42. static int fatReadSector(Fs_t *This, int sector, int slot, int bit, int dupe)
  43. {
  44.     int fat_start;
  45.  
  46.     dupe = (dupe + This->primaryFat) % This->num_fat;
  47.     fat_start = This->fat_start + This->fat_len * dupe;
  48.  
  49.     return force_read(This->Next,
  50.               (char *) 
  51.               (This->FatMap[slot].data + bit * This->sector_size),
  52.               (fat_start+sector) * This->sector_size,
  53.               This->sector_size);
  54. }
  55.  
  56.  
  57. static int fatWriteSector(Fs_t *This, int sector, int slot, int bit, int dupe)
  58. {
  59.     int fat_start;
  60.  
  61.     dupe = (dupe + This->primaryFat) % This->num_fat;
  62.     if(dupe && !This->writeAllFats)
  63.         return This->sector_size;
  64.  
  65.     fat_start = This->fat_start + This->fat_len * dupe;
  66.  
  67.     return force_write(This->Next,
  68.                (char *) 
  69.                (This->FatMap[slot].data + bit * This->sector_size),
  70.                (fat_start+sector)*This->sector_size,
  71.                This->sector_size);
  72. }
  73.  
  74.  
  75. enum mode_t { FAT_ACCESS_READ, FAT_ACCESS_WRITE };
  76.  
  77. static unsigned char *loadSector(Fs_t *This,
  78.                  unsigned int sector, enum mode_t mode,
  79.                  int recurs)
  80. {
  81.     int slot, bit, i, ret;
  82.  
  83.     if(locate(This,sector, &slot, &bit) < 0)
  84.         return 0;
  85.     if(!This->FatMap[slot].data) {
  86.         /* allocate the storage space */
  87.         This->FatMap[slot].data = 
  88.             malloc(This->sector_size * SECT_PER_ENTRY);
  89.         if(!This->FatMap[slot].data)
  90.             return 0;           
  91.     }
  92.  
  93.     if(! (This->FatMap[slot].valid & (1 << bit))) {
  94.         ret = -1;
  95.         for(i=0; i< This->num_fat; i++) {
  96.             /* read the sector */
  97.             ret = fatReadSector(This, sector, slot, bit, i);
  98.  
  99.             if(ret != This->sector_size) {
  100.                 fprintf(stderr,
  101.                     "Error reading fat number %d\n", i);
  102.                 continue;
  103.             }
  104.             break;
  105.         }
  106.  
  107.         /* all copies bad.  Return error */
  108.         if(ret != This->sector_size)
  109.             return 0;
  110.  
  111.         This->FatMap[slot].valid |= 1 << bit;
  112.         /* do some prefetching  */
  113.         if(!recurs)
  114.             loadSector(This, sector+1, mode, 1);
  115.     }
  116.  
  117.     if(mode == FAT_ACCESS_WRITE)
  118.         This->FatMap[slot].dirty |= 1 << bit;
  119.     return This->FatMap[slot].data + bit * This->sector_size;
  120. }
  121.  
  122.  
  123. static unsigned char *getAddress(Fs_t *Stream,
  124.                  unsigned int num, enum mode_t mode)
  125. {
  126.     unsigned char *ret;
  127.     int offset, sector;
  128.  
  129.     offset = num % Stream->sector_size;
  130.     sector = num / Stream->sector_size;
  131.     ret = loadSector(Stream, sector, mode, 0);
  132.     if(!ret)
  133.         return 0;
  134.     else
  135.         return ret+offset;
  136. }
  137.  
  138.  
  139. /*
  140.  * Fat 12 encoding:
  141.  *    |    byte n     |   byte n+1    |   byte n+2    |
  142.  *    |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
  143.  *    | | | | | | | | | | | | | | | | | | | | | | | | |
  144.  *    | n+0.0 | n+0.5 | n+1.0 | n+1.5 | n+2.0 | n+2.5 |
  145.  *        \_____  \____   \______/________/_____   /
  146.  *          ____\______\________/   _____/  ____\_/
  147.  *         /     \      \          /       /     \
  148.  *    | n+1.5 | n+0.0 | n+0.5 | n+2.0 | n+2.5 | n+1.0 |
  149.  *    |      FAT entry k      |    FAT entry k+1      |
  150.  */
  151.  
  152.  /*
  153.  * Get and decode a FAT (file allocation table) entry.  Returns the cluster
  154.  * number on success or 1 on failure.
  155.  */
  156.  
  157. static unsigned int fat12_decode(Fs_t *Stream, unsigned int num)
  158. {
  159.     unsigned int start = num * 3 / 2;
  160.     unsigned char *address0 = getAddress(Stream, start, FAT_ACCESS_READ);
  161.     unsigned char *address1 = getAddress(Stream, start+1, FAT_ACCESS_READ);
  162.  
  163.     if (num < 2 || !address0 || !address1 || num > Stream->num_clus+1) {
  164.         fprintf(stderr,"Bad address %d\n", num);
  165.         return 1;
  166.     }
  167.  
  168.     if (num & 1)
  169.         return (((*address1) & 0xff) << 4) | (((*address0) & 0xf0)>>4);
  170.     else
  171.         return (((*address1) & 0xf) << 8) | ((*address0) & 0xff );
  172. }
  173.  
  174.  
  175.  
  176.  
  177. /*
  178.  * Puts a code into the FAT table.  Is the opposite of fat_decode().  No
  179.  * sanity checking is done on the code.  Returns a 1 on error.
  180.  */
  181. static int fat12_encode(Fs_t *Stream, unsigned int num, unsigned int code)
  182. {
  183.     DeclareThis(Fs_t);
  184.  
  185.     int start = num * 3 / 2;
  186.     unsigned char *address0 = getAddress(Stream, start, FAT_ACCESS_WRITE);
  187.     unsigned char *address1 = getAddress(Stream, start+1, FAT_ACCESS_WRITE);
  188.  
  189.     if (num < 2 || !address0 || !address1 || num >This->num_clus+1) {
  190.         fprintf(stderr,"Bad address %d\n", num);
  191.         return 1;
  192.     }
  193.  
  194.  
  195.     This->fat_dirty = 1;
  196.     if (num & 1) {
  197.         /* (odd) not on byte boundary */
  198.         *address0 = (*address0 & 0x0f) | ((code << 4) & 0xf0);
  199.         *address1 = (code >> 4) & 0xff;
  200.     } else {
  201.         /* (even) on byte boundary */
  202.         *address0 = code & 0xff;
  203.         *address1 = (*address1 & 0xf0) | ((code >> 8) & 0x0f);
  204.     }
  205.     return 0;
  206. }
  207.  
  208.  
  209. /*
  210.  * Fat 16 encoding:
  211.  *    |    byte n     |   byte n+1    |
  212.  *    |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
  213.  *    | | | | | | | | | | | | | | | | |
  214.  *    |         FAT entry k           |
  215.  */
  216.  
  217. static unsigned int fat16_decode(Fs_t *Stream, unsigned int num)
  218. {
  219.     unsigned int start = num * 2;
  220.     unsigned char *address = getAddress(Stream, start, FAT_ACCESS_READ);
  221.     /* always aligned */
  222.  
  223.     if (num < 2 || !address || num > Stream->num_clus+1) {
  224.         fprintf(stderr,"Bad address %d\n", num);
  225.         return 1;
  226.     }
  227.     return _WORD(address);
  228. }
  229.  
  230. static int fat16_encode(Fs_t *Stream, unsigned int num, unsigned int code)
  231. {       
  232.     DeclareThis(Fs_t);
  233.  
  234.     int start = num * 2;
  235.     unsigned char *address = getAddress(Stream, start, FAT_ACCESS_WRITE);
  236.  
  237.     if (num < 2 || !address || num >This->num_clus+1) {
  238.         fprintf(stderr,"Bad address %d\n", num);
  239.         return 1;
  240.     }
  241.  
  242.     This->fat_dirty = 1;
  243.     set_word(address, code);
  244.     return 0;
  245. }
  246.  
  247.  
  248. /*
  249.  * Fat 32 encoding
  250.  */
  251. static unsigned int fat32_decode(Fs_t *Stream, unsigned int num)
  252. {
  253.     unsigned int start = num * 4;
  254.     unsigned char *address = getAddress(Stream, start, FAT_ACCESS_READ);
  255.     /* always aligned */
  256.  
  257.     if (num < 2 || !address || num > Stream->num_clus+1) {
  258.         fprintf(stderr,"Bad address %d\n", num);
  259.         return 1;
  260.     }
  261.     return _DWORD(address);
  262. }
  263.  
  264. static int fat32_encode(Fs_t *Stream, unsigned int num, unsigned int code)
  265. {       
  266.     DeclareThis(Fs_t);
  267.     int oldcode;
  268.  
  269.     int start = num * 4;
  270.     unsigned char *address = getAddress(Stream, start, FAT_ACCESS_WRITE);
  271.  
  272.     if (num < 2 || !address || num >This->num_clus+1) {
  273.         fprintf(stderr,"Bad address %d\n", num);
  274.         return 1;
  275.     }
  276.     This->fat_dirty = 1;
  277.     oldcode = _DWORD(address);
  278.     set_dword(address, code);
  279.  
  280.     if(Stream->infoSector) {
  281.         int free;
  282.         free = _DWORD(Stream->infoSector->count);
  283.         if(code != MAX32)
  284.             /* put the pointer on the sector actually allocated,
  285.              * and not on the previous one, unless we are at the
  286.              * end. */
  287.             num = code;
  288.         if(code)
  289.             set_dword(Stream->infoSector->pos,num);
  290.         if(free != MAX32) {
  291.             if(oldcode)
  292.                 free++;
  293.             if(code)
  294.                 free--;
  295.             set_dword(Stream->infoSector->count, free);
  296.         }
  297.     }
  298.  
  299.     return 0;
  300. }
  301.  
  302.  
  303. /*
  304.  * Write the FAT table to the disk.  Up to now the FAT manipulation has
  305.  * been done in memory.  All errors are fatal.  (Might not be too smart
  306.  * to wait till the end of the program to write the table.  Oh well...)
  307.  */
  308.  
  309. void fat_write(Fs_t *This)
  310. {
  311.     int i, j, dups, ret, bit, slot;
  312.     int fat_start;
  313.  
  314.     if (!This->fat_dirty)
  315.         return;
  316.  
  317.     dups = This->num_fat;
  318.     if (This->fat_error)
  319.         dups = 1;
  320.  
  321.  
  322.     for(i=0; i<dups; i++){
  323.         j = 0;
  324.         fat_start = This->fat_start + i*This->fat_len;
  325.         for(slot=0;j<This->fat_len;slot++) {
  326.             if(!This->FatMap[slot].dirty) {
  327.                 j += SECT_PER_ENTRY;
  328.                 continue;
  329.             }
  330.             for(bit=0; 
  331.                 bit < SECT_PER_ENTRY && j<This->fat_len;
  332.                 bit++,j++) {
  333.                 if(!(This->FatMap[slot].dirty & (1 << bit)))
  334.                     continue;
  335.                 ret = fatWriteSector(This,j,slot, bit, i);
  336.                 if (ret < This->sector_size){
  337.                     if (ret < 0 ){
  338.                         perror("error in fat_write");
  339.                         exit(1);
  340.                     } else {
  341.                         fprintf(stderr,
  342.                             "end of file in fat_write\n");
  343.                         exit(1);
  344.                     }
  345.                 }
  346.                 /* if last dupe, zero it out */
  347.                 if(i==dups-1)
  348.                     This->FatMap[slot].dirty &= ~(1<<bit);
  349.             }
  350.         }     
  351.     }
  352.     /* write the info sector, if any */
  353.     if(This->infoSector) {
  354.         if(force_write(This->Next,
  355.                    (char *)This->infoSector,
  356.                    This->infoSectorLoc*This->sector_size,
  357.                    This->sector_size) !=
  358.            This->sector_size)
  359.             fprintf(stderr,"Trouble writing the info sector\n");
  360.     }
  361.     This->fat_dirty = 0;
  362. }
  363.  
  364.  
  365.  
  366. /*
  367.  * Zero-Fat
  368.  * Used by mformat.
  369.  */
  370. int zero_fat(Fs_t *Stream, int media_descriptor)
  371. {
  372.     int i, j;
  373.     int fat_start;
  374.     unsigned char *buf;
  375.  
  376.     buf = safe_malloc(Stream->sector_size);
  377.     for(i=0; i< Stream->num_fat; i++) {
  378.         fat_start = Stream->fat_start + i*Stream->fat_len;
  379.         for(j = 0; j < Stream->fat_len; j++) {
  380.             if(j <= 1)
  381.                 memset(buf, 0, Stream->sector_size);
  382.             if(!j) {
  383.                 buf[0] = media_descriptor;
  384.                 buf[2] = buf[1] = 0xff;
  385.                 if(Stream->fat_bits > 12)
  386.                     buf[3] = 0xff;
  387.                 if(Stream->fat_bits > 16) {
  388.                     buf[4] = 0xff;
  389.                     buf[5] = 0xff;
  390.                     buf[6] = 0xff;
  391.                     buf[7] = 0xff;
  392.                 }
  393.             }
  394.  
  395.             if(force_write(Stream->Next,
  396.                        (char *)buf,
  397.                        (fat_start + j) * Stream->sector_size,
  398.                        Stream->sector_size) !=
  399.                Stream->sector_size) {
  400.                 fprintf(stderr,
  401.                     "Trouble initializing a FAT sector\n");
  402.                 free(buf);
  403.                 return -1;
  404.             }
  405.         }
  406.     }
  407.     
  408.     free(buf);
  409.     Stream->FatMap = GetFatMap(Stream);
  410.     if (Stream->FatMap == NULL) {
  411.         perror("alloc fat map");
  412.         return -1;
  413.     }
  414.     return 0;
  415. }
  416.  
  417.  
  418. void set_fat12(Fs_t *This)
  419. {
  420.     This->fat_bits = 12;
  421.     This->end_fat = 0xfff;
  422.     This->last_fat = 0xff6;
  423.     This->fat_decode = fat12_decode;
  424.     This->fat_encode = fat12_encode;
  425. }
  426.  
  427. static inline int try_fat12(Fs_t *This)
  428. {
  429.     if (This->num_clus > FAT12)
  430.         /* too many clusters */
  431.         return -2;
  432.     set_fat12(This);
  433.     return 0;
  434. }
  435.  
  436. void set_fat16(Fs_t *This)
  437. {
  438.     This->fat_bits = 16;
  439.     This->end_fat = 0xffff;
  440.     This->last_fat = 0xfff6;
  441.     This->fat_decode = fat16_decode;
  442.     This->fat_encode = fat16_encode;
  443. }
  444.  
  445. static inline int try_fat16(Fs_t *This)
  446. {
  447.     unsigned char *address;
  448.  
  449.     set_fat16(This);
  450.     if(This->fat_len < NEEDED_FAT_SIZE(This))
  451.         return -2;
  452.     address = getAddress(This, 3, FAT_ACCESS_READ);
  453.     if(!address || address[3] != 0xff)
  454.         return -1;
  455.     return 0;
  456. }
  457.  
  458. void set_fat32(Fs_t *This)
  459. {
  460.     This->fat_bits = 32;
  461.     This->end_fat = 0xffffffff;
  462.     This->last_fat = 0xfffffff6;
  463.     
  464.     This->fat_decode = fat32_decode;
  465.     This->fat_encode = fat32_encode;           
  466. }
  467.  
  468.  
  469. static inline int check_fat(Fs_t *This, int verbose)
  470. {
  471.     /* 
  472.      * This is only a sanity check.  For disks with really big FATs,
  473.      * there is no point in checking the whole FAT.
  474.      */
  475.  
  476.     int i, f, tocheck;
  477.     if(mtools_skip_check)
  478.         return 0;
  479.     
  480.     tocheck = This->num_clus;
  481.     if(tocheck > 4096)
  482.         tocheck = 4096;
  483.  
  484.     for ( i= 3 ; i < tocheck; i++){
  485.         f = This->fat_decode(This,i);
  486.         if (f < This->last_fat && f > This->num_clus){
  487.             if(verbose){
  488.                 fprintf(stderr,
  489.                     "Cluster # at %d too big(%#x)\n", i,f);
  490.                 fprintf(stderr,"Probably non MS-DOS disk\n");
  491.             }
  492.             return -1;
  493.         }
  494.     }
  495.     return 0;
  496. }
  497.  
  498. static inline int try_fat(Fs_t *This, int bits, int verbose)
  499. {
  500.     int ret;
  501.  
  502.     if (bits == 12)
  503.         ret = try_fat12(This);
  504.     else
  505.         ret = try_fat16(This);
  506.     if(ret)
  507.         return ret;
  508.     else
  509.         return check_fat(This, verbose);
  510. }
  511.  
  512. /*
  513.  * Read the first sector of FAT table into memory.  Crude error detection on
  514.  * wrong FAT encoding scheme.
  515.  */
  516. static int check_media_type(Fs_t *This, struct bootsector *boot, 
  517.                 unsigned int tot_sectors)
  518. {
  519.     unsigned char *address;
  520.  
  521.     This->num_clus = (tot_sectors - This->clus_start) / This->cluster_size;
  522.  
  523.     This->FatMap = GetFatMap(This);
  524.     if (This->FatMap == NULL) {
  525.         perror("alloc fat map");
  526.         return -1;
  527.     }
  528.  
  529.     address = getAddress(This, 0, FAT_ACCESS_READ);
  530.     if(!address) {
  531.         fprintf(stderr,
  532.             "Could not read first FAT sector\n");
  533.         return -1;
  534.     }
  535.  
  536.     if (!mtools_skip_check && (address[0] || address[1] || address[2])) {
  537.         if((address[0] != boot->descr && boot->descr >= 0xf0 &&
  538.             (address[0] != 0xf9 || boot->descr != 0xf0)) ||
  539.            address[0] < 0xf0){
  540.             fprintf(stderr,
  541.                 "Bad media type, probably non-MSDOS disk\n");
  542.             return -1;
  543.         }
  544.         if(address[1] != 0xff || address[2] != 0xff){
  545.             fprintf(stderr,"Initial byte of fat is not 0xff\n");
  546.             return -1;
  547.         }
  548.     }
  549.     return 0;
  550. }
  551.  
  552.  
  553.  
  554. static int fat_32_read(Fs_t *This, struct bootsector *boot, 
  555.                unsigned int tot_sectors)
  556. {
  557.     This->fat_len = DWORD(ext.fat32.bigFat);
  558.     This->writeAllFats = !(boot->ext.fat32.extFlags[0] & 0x80);
  559.     This->primaryFat = boot->ext.fat32.extFlags[0] & 0xf;
  560.     This->rootCluster = DWORD(ext.fat32.rootCluster);
  561.     This->clus_start = This->fat_start + This->num_fat * This->fat_len;
  562.  
  563.     /* read the info sector */
  564.     This->infoSectorLoc = WORD(ext.fat32.infoSector);
  565.     if(This->infoSectorLoc > 0) {
  566.         This->infoSector = (InfoSector_t *) malloc(This->sector_size);
  567.         if(This->infoSector) {
  568.             if(force_read(This->Next,
  569.                       (char *)This->infoSector,
  570.                       This->infoSectorLoc*This->sector_size,
  571.                       This->sector_size) !=
  572.                This->sector_size) {
  573.                 free(This->infoSector);
  574.                 This->infoSector = 0;
  575.             }
  576.             if(_DWORD(This->infoSector->signature) != 
  577.                INFOSECT_SIGNATURE){
  578.                 free(This->infoSector);
  579.                 This->infoSector = 0;
  580.             }
  581.         }
  582.     }
  583.     
  584.     set_fat32(This);
  585.     if(check_media_type(This,boot, tot_sectors))
  586.         return -1;
  587.     return 0;
  588. }
  589.  
  590.  
  591. static int old_fat_read(Fs_t *This, struct bootsector *boot, int fat_bits,
  592.             unsigned int tot_sectors, int nodups)
  593. {
  594.     int ret, ret2;
  595.  
  596.     This->writeAllFats = 1;
  597.     This->primaryFat = 0;
  598.     This->dir_start = This->fat_start + This->num_fat * This->fat_len;
  599.     This->clus_start = This->dir_start + This->dir_len;
  600.  
  601.     if(nodups)
  602.         This->num_fat = 1;
  603.  
  604.     if(check_media_type(This,boot, tot_sectors))
  605.         return -1;
  606.  
  607.     switch(fat_bits){
  608.         case 12:
  609.         case 16:
  610.             ret = try_fat(This, fat_bits, 1);
  611.             break;
  612.         case -12:
  613.         case -16:
  614.             ret = try_fat(This, -fat_bits, 1);
  615.             break;
  616.         case 0:
  617.             /* no size given in the configuration file.
  618.              * Figure out a first guess */
  619.             
  620.             if (boot->descr < 0xf0 || boot->ext.old.dos4 !=0x29)
  621.                 fat_bits = 12; /* old DOS */
  622.             else if (!strncmp(boot->ext.old.fat_type, 
  623.                       "FAT12   ", 8))
  624.                 fat_bits = 12;
  625.             else if (!strncmp (boot->ext.old.fat_type, 
  626.                        "FAT16   ", 8))
  627.                 fat_bits = 16;
  628.             else
  629.                 fat_bits = 12;
  630.             
  631.             ret = try_fat(This, fat_bits, 1);
  632.             if(!ret)
  633.                 break;
  634.  
  635.             fat_bits = 28 - fat_bits;
  636.             ret2 = try_fat(This, fat_bits, 1);
  637.             if(ret2 >= ret){ 
  638.                 /* second try didn't fail as badly as first */
  639.                 ret = ret2;
  640.                 break;
  641.             }
  642.  
  643.             /* revert to first try because that one failed
  644.              * less badly */
  645.             fat_bits = 28 - fat_bits;
  646.             ret = try_fat(This, fat_bits, 1);
  647.             break;
  648.         default:
  649.             fprintf(stderr,"%d fat bits not supported\n", fat_bits);
  650.             return -1;
  651.     }
  652.  
  653.     if(ret == -2) {
  654.         /* the return value suggests a different fat,
  655.          * independently of the read data */
  656.         if(fat_bits > 0 ){                
  657.             fprintf(stderr,
  658.                 "%c: %d bit FAT. sure ? (Use -%d in the device configuration file to bypass.)\n",
  659.                 This->drive, fat_bits, fat_bits);
  660.             return -2;
  661.         } else if(fat_bits >= 0)
  662.             return -1;
  663.     }
  664.  
  665.     /*
  666.      * Let's see if the length of the FAT table is appropriate for
  667.      * the number of clusters and the encoding scheme.
  668.      * Older versions of mtools goofed this up. If the env var
  669.      * MTOOLS_FAT_COMPATIBILITY is defined, skip this check in order to read
  670.      * disks formatted by an old version.
  671.      */
  672.     if(!mtools_fat_compatibility &&
  673.        This->fat_len > NEEDED_FAT_SIZE(This) + 1){
  674.         fprintf(stderr,
  675.             "fat_read: Wrong FAT encoding for drive %c."
  676.             "(len=%d instead of %d?)\n",
  677.             This->drive, This->fat_len, NEEDED_FAT_SIZE(This));
  678.         fprintf(stderr,
  679.             "Set MTOOLS_FAT_COMPATIBILITY to suppress"
  680.             " this message\n");
  681.         return -1;
  682.     }
  683.     return 0;
  684. }
  685.  
  686.  
  687.  
  688. /*
  689.  * Read the first sector of the  FAT table into memory and initialize 
  690.  * structures.
  691.  */
  692. int fat_read(Fs_t *This, struct bootsector *boot, int fat_bits,
  693.          unsigned int tot_sectors, int nodups)
  694. {
  695.     This->fat_error = 0;
  696.     This->fat_dirty = 0;
  697.     This->infoSector = 0;
  698.  
  699.     if(This->fat_len)
  700.         return old_fat_read(This, boot, fat_bits, tot_sectors, nodups);
  701.     else
  702.         return fat_32_read(This, boot, tot_sectors);
  703. }
  704.  
  705.  
  706. unsigned int get_next_free_cluster(Fs_t *This, unsigned int last)
  707. {
  708.     int i;
  709.  
  710.     if(This->infoSector)
  711.         last = _DWORD(This->infoSector->pos);
  712.  
  713.     if ( last < 2)
  714.         last = 1;
  715.  
  716.     for (i=last+1; i< This->num_clus+2; i++){
  717.         if (!This->fat_decode(This, i))
  718.             return i;
  719.     }
  720.     for(i=2; i < last+1; i++){
  721.         if (!This->fat_decode(This, i))
  722.             return i;
  723.     }
  724.     fprintf(stderr,"No free cluster\n");
  725.     return 1;
  726. }
  727.  
  728. int fat_error(Stream_t *Dir)
  729. {
  730.     Stream_t *Stream = GetFs(Dir);
  731.     DeclareThis(Fs_t);
  732.  
  733.     if(This->fat_error)
  734.         fprintf(stderr,"Fat error detected\n");
  735.  
  736.     return This->fat_error;
  737. }
  738.  
  739. int fat32RootCluster(Stream_t *Dir)
  740. {
  741.     Stream_t *Stream = GetFs(Dir);
  742.     DeclareThis(Fs_t);
  743.     
  744.     if(This->fat_bits == 32)
  745.         return This->rootCluster;
  746.     else
  747.         return 0;
  748. }
  749.  
  750.  
  751. /*
  752.  * Get the amount of free space on the diskette
  753.  */
  754.  
  755. unsigned long getfree(Stream_t *Dir)
  756. {
  757.     Stream_t *Stream = GetFs(Dir);
  758.     DeclareThis(Fs_t);
  759.     register unsigned int i;
  760.     size_t total;
  761.  
  762.     if(This->infoSector && 
  763.        (total = _DWORD(This->infoSector->count)) != MAX32)
  764.         return total * This->sector_size * This->cluster_size;
  765.  
  766.     total = 0L;
  767.     for (i = 2; i < This->num_clus + 2; i++) {
  768.         /* if fat_decode returns zero */
  769.         if (!This->fat_decode(This,i))
  770.             total += This->cluster_size;
  771.     }
  772.  
  773.     if(This->infoSector)
  774.         set_dword(This->infoSector->count, total);
  775.  
  776.     return(total * This->sector_size);
  777. }
  778.  
  779.  
  780. /*
  781.  * Ensure that there is a minimum of total sectors free
  782.  */
  783.  
  784. unsigned long getfreeMin(Stream_t *Dir, size_t ref)
  785. {
  786.     Stream_t *Stream = GetFs(Dir);
  787.     DeclareThis(Fs_t);
  788.     register unsigned int i, last;
  789.     size_t total, ref2;
  790.  
  791.     ref2 = ref  / (This->sector_size * This->cluster_size);
  792.     if(ref % (This->sector_size * This->cluster_size))
  793.         ref2++;
  794.  
  795.     if(This->infoSector && 
  796.        (total = _DWORD(This->infoSector->count)) != MAX32)
  797.         return total >= ref2;
  798.  
  799.     total = 0L;
  800.  
  801.     /* we start at the same place where we'll start later to actually
  802.      * allocate the sectors.  That way, the same sectors of the FAT, which
  803.      * are already loaded during getfreeMin will be able to be reused 
  804.      * during get_next_free_cluster */
  805.  
  806.     if(This->infoSector)
  807.         last = _DWORD(This->infoSector->pos);
  808.     else
  809.         last = 1;
  810.  
  811.     
  812.     if ( last < 2)
  813.         last = 1;
  814.     for (i=last+1; i< This->num_clus+2; i++){
  815.         if (!This->fat_decode(This, i))
  816.             total++;
  817.         if(total >= ref2)
  818.             return 1;
  819.     }
  820.     for(i=2; i < last+1; i++){
  821.         if (!This->fat_decode(This, i))
  822.             total++;
  823.         if(total >= ref2)
  824.             return 1;
  825.     }
  826.     return 0;
  827. }
  828.