Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

fat.c

Go to the documentation of this file.
00001 /*! \file fat.c \brief FAT16/32 file system driver. */
00002 //*****************************************************************************
00003 //
00004 // File Name    : 'fat.c'
00005 // Title        : FAT16/32 file system driver
00006 // Author       : Pascal Stang
00007 // Date         : 11/07/2000
00008 // Revised      : 12/12/2000
00009 // Version      : 0.3
00010 // Target MCU   : ATmega103 (should work for Atmel AVR Series)
00011 // Editor Tabs  : 4
00012 //
00013 // This code is based in part on work done by Jesper Hansen for his
00014 //      YAMPP MP3 player project.
00015 //
00016 // NOTE: This code is currently below version 1.0, and therefore is considered
00017 // to be lacking in some functionality or documentation, or may not be fully
00018 // tested.  Nonetheless, you can expect most functions to work.
00019 //
00020 // This code is distributed under the GNU Public License
00021 //      which can be found at http://www.gnu.org/licenses/gpl.txt
00022 //
00023 //*****************************************************************************
00024 
00025 
00026 #include <string.h>
00027 
00028 #include "device.h"
00029 #include "rprintf.h"
00030 #include "debug.h"
00031 
00032 #include "fat.h"
00033 #include "fatconf.h"
00034 
00035 // globals
00036 // buffers
00037 //unsigned char *SectorBuffer  =        (unsigned char *) FAT_SECTOR_BUFFER_ADDR;
00038 //unsigned char *FileNameBuffer =       (unsigned char *) FAT_FILENAME_BUFFER_ADDR;
00039 //unsigned char *PathNameBuffer =       (unsigned char *) FAT_PATHNAME_BUFFER_ADDR;
00040 //unsigned char *FatCacheBuffer =       (unsigned char *) FAT_CACHE_BUFFER_ADDR;
00041 unsigned char SectorBuffer[0x200];
00042 unsigned char FileNameBuffer[0x100];
00043 unsigned char PathNameBuffer[0x100];
00044 unsigned char FatCacheBuffer[0x200];
00045 
00046 struct fatFsInfo
00047 {
00048     unsigned long FirstDataSector;
00049     unsigned short BytesPerSector;
00050     unsigned short SectorsPerCluster;
00051     unsigned long FirstFATSector;
00052     unsigned long SectorsPerFat;
00053     unsigned long RootDirStartCluster;
00054     unsigned long FatInCache;
00055     unsigned long FatMask;
00056     unsigned char Fat32Enabled;
00057     unsigned char NumberOfFats;
00058 
00059     DevDisk_t devdisk;
00060 //};
00061 } GNUC_PACKED;
00062 
00063 typedef struct FatFsInfo FatFsInfo_t;
00064 
00065 // filesystem constants/metrics
00066 struct fatFsInfo FatFsInfo;
00067 
00068 // operating variables
00069 unsigned long CurrentDirStartCluster;   //< current directory starting cluster
00070 struct FileInfo_s FileInfo;             //< file information for last file accessed
00071 
00072 
00073 /*************************************************************************/
00074 /*************************************************************************/
00075 
00076 unsigned char fatInit(DevDisk_t* devdisk)
00077 {
00078     //bios parameter block
00079     struct bpb710 *bpb;
00080 
00081     // initialize disk access interface
00082     FatFsInfo.devdisk = *devdisk;
00083 
00084     rprintfProgStrM("DevDisk pointers\r\n");
00085     rprintfu32((unsigned long)devdisk->ReadSector);
00086     rprintfu32((unsigned long)devdisk->WriteSector);
00087     rprintfCRLF();
00088 
00089     FatFsInfo.FatInCache = 0;
00090 
00091     // Read the BootSector
00092     FatFsInfo.devdisk.ReadSector(0, 1, SectorBuffer);
00093     bpb = (struct bpb710 *) ((struct bootsector710 *) SectorBuffer)->bsBPB;
00094 
00095     // setup global disk constants
00096     if(bpb->bpbFATsecs)
00097     {
00098         // bpbFATsecs (16-bit) is non-zero and is therefore valid
00099         FatFsInfo.SectorsPerFat = bpb->bpbFATsecs;
00100         // this volume should be FAT16
00101         // first directory cluster is 2 by default (clusters range 2->big)
00102         FatFsInfo.RootDirStartCluster = CLUST_FIRST;
00103         // push data sector pointer to end of root directory area
00104         //FirstDataSector += (bpb->bpbRootDirEnts)/DIRENTRIES_PER_SECTOR;
00105         FatFsInfo.Fat32Enabled = FALSE;
00106         // set FAT mask for 16-bit
00107         FatFsInfo.FatMask = FAT16_MASK;
00108     }
00109     else
00110     {
00111         // bpbFATsecs is zero, real value is in bpbBigFATsecs (32-bit)
00112         FatFsInfo.SectorsPerFat = bpb->bpbBigFATsecs;
00113         // this volume must be FAT32
00114         // bpbRootClust field exists in FAT32 bpb710, but not in lesser bpb's
00115         FatFsInfo.RootDirStartCluster = bpb->bpbRootClust;
00116         // push data sector pointer to end of root directory area
00117         // need this? FirstDataSector += (bpb->bpbRootDirEnts)/DIRENTRIES_PER_SECTOR;
00118         FatFsInfo.Fat32Enabled = TRUE;
00119         // set FAT mask for 32-bit
00120         FatFsInfo.FatMask = FAT32_MASK;
00121     }
00122     FatFsInfo.SectorsPerCluster     = bpb->bpbSecPerClust;
00123     FatFsInfo.BytesPerSector        = bpb->bpbBytesPerSec;
00124     FatFsInfo.FirstFATSector        = bpb->bpbResSectors;
00125     FatFsInfo.NumberOfFats          = bpb->bpbFATs;
00126     FatFsInfo.FirstDataSector       = bpb->bpbResSectors + FatFsInfo.NumberOfFats * FatFsInfo.SectorsPerFat;
00127 
00128     // set current directory to root (\)
00129     CurrentDirStartCluster = FatFsInfo.RootDirStartCluster;
00130     PathNameBuffer[0] = '\\';
00131     PathNameBuffer[1] = 0;
00132 
00133     // do debug
00134 #ifdef DEBUG_FAT
00135     rprintfProgStrM("---------- Disk/Partition Information ----------\r\n");
00136     rprintfProgStrM("Volume/Part Size: ");  rprintfu32(FatFsInfo.devdisk.numsectors);       rprintfCRLF();
00137     rprintfProgStrM("---------- FAT Volume Information --------------\r\n");
00138     rprintfProgStrM("Reserved Sectors: ");  rprintfu16(bpb->bpbResSectors);             rprintfCRLF();
00139     rprintfProgStrM("FatSectors      : ");  rprintfu16(bpb->bpbFATsecs);                rprintfCRLF();
00140     rprintfProgStrM("BigFatSectors   : ");  rprintfu32(bpb->bpbBigFATsecs);             rprintfCRLF();
00141     rprintfProgStrM("Bytes/Sector    : ");  rprintfu16(FatFsInfo.BytesPerSector);       rprintfCRLF();
00142     rprintfProgStrM("First Fat Sector: ");  rprintfu32(FatFsInfo.FirstFATSector);       rprintfCRLF();
00143     rprintfProgStrM("Number of Fats  : ");  rprintfu08(FatFsInfo.NumberOfFats);         rprintfCRLF();
00144     rprintfProgStrM("Sectors/FAT     : ");  rprintfu32(FatFsInfo.SectorsPerFat);        rprintfCRLF();
00145     rprintfProgStrM("First Data Sect : ");  rprintfu32(FatFsInfo.FirstDataSector);      rprintfCRLF();
00146     rprintfProgStrM("Sectors/Cluster : ");  rprintfu08(FatFsInfo.SectorsPerCluster);    rprintfCRLF();
00147     rprintfProgStrM("RootDirStartClus: ");  rprintfu32(FatFsInfo.RootDirStartCluster);  rprintfCRLF();
00148 #endif
00149 
00150     return 0;   
00151 }
00152 
00153 
00154 //////////////////////////////////////////////////////////////
00155 
00156 unsigned char fatGetDirEntry(unsigned short entry)
00157 {
00158     unsigned long sector;
00159     struct direntry *de = 0;    // avoid compiler warning by initializing
00160     struct winentry *we;
00161     unsigned char haveLongNameEntry;
00162     unsigned char gotEntry;
00163     unsigned short b;
00164     int i,index;
00165     char *fnbPtr;
00166     unsigned short entrycount = 0;
00167 
00168     // read dir data
00169 
00170     sector = fatClusterToSector(CurrentDirStartCluster);
00171 
00172     haveLongNameEntry = 0;
00173     gotEntry = 0;
00174 
00175     index = 16; // crank it up
00176     
00177     //while(entrycount < entry) 
00178     while(1)
00179     {
00180         if(index == 16) // time for next sector ?
00181         {
00182             FatFsInfo.devdisk.ReadSector(sector++, 1, SectorBuffer);
00183             de = (struct direntry *) SectorBuffer;
00184             index = 0;
00185         }
00186         
00187         // check the status of this directory entry slot
00188         if(de->deName[0] == 0x00)
00189         {
00190             // slot is empty and this is the end of directory
00191             gotEntry = 0;
00192             break;
00193         }
00194         else if(de->deName[0] == 0xE5)
00195         {
00196             // this is an empty slot
00197             // do nothing and move to the next one
00198         }
00199         else
00200         {
00201             // this is a valid and occupied entry
00202             // is it a part of a long file/dir name?
00203             if(de->deAttributes == ATTR_LONG_FILENAME)
00204             {
00205                 // we have a long name entry
00206                 // cast this directory entry as a "windows" (LFN: LongFileName) entry
00207                 we = (struct winentry *) de;
00208                 
00209                 b = WIN_ENTRY_CHARS*( (we->weCnt-1) & 0x0f);        // index into string
00210                 fnbPtr = &FileNameBuffer[b];
00211                 for (i=0;i<5;i++)   *fnbPtr++ = we->wePart1[i*2];   // copy first part
00212                 for (i=0;i<6;i++)   *fnbPtr++ = we->wePart2[i*2];   // second part
00213                 for (i=0;i<2;i++)   *fnbPtr++ = we->wePart3[i*2];   // and third part
00214                 if (we->weCnt & WIN_LAST) *fnbPtr = 0;              // in case dirnamelength is multiple of 13, add termination
00215                 if ((we->weCnt & 0x0f) == 1) haveLongNameEntry = 1; // flag that we have a complete long name entry set
00216             }
00217             else
00218             {
00219                 // we have a short name entry
00220                 
00221                 // check if this is the short name entry corresponding
00222                 // to the end of a multi-part long name entry
00223                 if(haveLongNameEntry)
00224                 {
00225                     // a long entry name has been collected
00226                     if(entrycount == entry)     
00227                     {
00228                         // desired entry has been found, break out
00229                         gotEntry = 1;
00230                         break;
00231                     }
00232                     // otherwise
00233                     haveLongNameEntry = 0;  // clear long name flag
00234                     entrycount++;           // increment entry counter      
00235                 }
00236                 else
00237                 {
00238                     // entry is a short name (8.3 format) without a
00239                     // corresponding multi-part long name entry
00240                     fnbPtr = FileNameBuffer;
00241                     for (i=0;i<8;i++)   *fnbPtr++ = de->deName[i];      // copy name
00242                     *fnbPtr++ = '.';                                    // insert '.'
00243                     for (i=0;i<3;i++)   *fnbPtr++ = de->deExtension[i]; // copy extension
00244                     *fnbPtr = 0;                                        // null-terminate
00245 
00246                     if(entrycount == entry)     
00247                     {
00248                         // desired entry has been found, break out
00249                         gotEntry = 1;
00250                         break;
00251                     }
00252                     // otherwise
00253                     entrycount++;           // increment entry counter      
00254                 }
00255             }
00256         }
00257         // next directory entry
00258         de++;
00259         // next index
00260         index++;
00261     }
00262     
00263     // we have a file/dir to return
00264     // store file/dir starting cluster (start of data)
00265     FileInfo.StartCluster = (unsigned long) ((unsigned long)de->deHighClust << 16) + de->deStartCluster;
00266     // store file/dir size
00267     // (note: size field for subdirectory entries is always zero)
00268     FileInfo.Size = de->deFileSize;
00269     // store file/dir attributes
00270     FileInfo.Attr = de->deAttributes;
00271     // store file/dir creation time
00272     FileInfo.CreateTime = de->deCTime[0] | de->deCTime[1]<<8;
00273     // store file/dir creation date
00274     FileInfo.CreateTime = de->deCDate[0] | de->deCDate[1]<<8;
00275 
00276     return gotEntry;
00277 }
00278 
00279 int fatCreateFile(unsigned char* filename, FileInfo_t* fileInfo)
00280 {
00281     unsigned long sector;
00282     struct direntry *de = 0;    // avoid compiler warning by initializing
00283     unsigned int index;
00284     unsigned char* strptr;
00285     unsigned char i;
00286     
00287     // find empty directory entry
00288     sector = fatClusterToSector(CurrentDirStartCluster);
00289 
00290     index = DIRENTRIES_PER_SECTOR;
00291 
00292     while(1)
00293     {
00294         if(index == DIRENTRIES_PER_SECTOR)  // time for next sector ?
00295         {
00296             FatFsInfo.devdisk.ReadSector(sector++, 1, SectorBuffer);
00297             de = (struct direntry *)SectorBuffer;
00298             index = 0;
00299         }
00300         
00301         // check the status of this directory entry slot
00302         if(de->deName[0] == SLOT_EMPTY)
00303         {
00304             // slot is empty and this is the end of the directory
00305             // need to make sure the next slot is written with a zero
00306             break;
00307         }
00308         else if(de->deName[0] == SLOT_DELETED)
00309         {
00310             // this is an empty slot, the entry was previously deleted
00311             break;
00312         }
00313         // empty/unused directory entry not yet found
00314         // move to the next one
00315         de++;
00316         index++;
00317     }
00318 
00319     // populate directory entry
00320     strptr = filename;
00321     // parse and fill filename
00322     for(i=0; i<8; i++)
00323     {
00324         if( (*strptr != '.') && (*strptr != 0) )
00325             de->deName[i] = *strptr++;
00326         else
00327             de->deName[i] = ' ';
00328     }
00329     // fill extension
00330     //strchr(filename, '.')
00331     if(*strptr == '.')
00332     {
00333         strptr++;
00334         de->deExtension[0] = *strptr++;
00335         de->deExtension[1] = *strptr++;
00336         de->deExtension[2] = *strptr++;
00337     }
00338     else
00339     {
00340         de->deExtension[0] = ' ';
00341         de->deExtension[1] = ' ';
00342         de->deExtension[2] = ' ';
00343     }
00344     // attributes
00345     de->deAttributes = fileInfo->Attr;
00346     // stuff
00347     de->deLowerCase = 0;
00348     // dates
00349     de->deCHundredth = 0;
00350     de->deCTime[0] = fileInfo->CreateTime;
00351     de->deCTime[1] = fileInfo->CreateTime>>8;
00352     de->deCDate[0] = fileInfo->CreateDate;
00353     de->deCDate[1] = fileInfo->CreateDate>>8;
00354     de->deADate[0] = 0;
00355     de->deADate[1] = 0;
00356     de->deMTime[0] = 0;
00357     de->deMTime[1] = 0;
00358     de->deMDate[0] = 0;
00359     de->deMDate[1] = 0;
00360     // file size
00361     de->deFileSize = fileInfo->Size;
00362     // set file's start cluster
00363     de->deStartCluster = fileInfo->StartCluster;
00364     de->deHighClust = fileInfo->StartCluster>>16;
00365 
00366     // write directory entry back to disk
00367     FatFsInfo.devdisk.WriteSector(--sector, 1, SectorBuffer);
00368 
00369     return 0;
00370 }
00371 
00372 int fatFormat(unsigned long volsize)
00373 {
00374     unsigned long i,j,fatsecs;
00375     unsigned long sector;
00376 
00377     struct bootsector710 *bs;
00378     struct bpb710* bpb;
00379 
00380     // FIRST STAGE
00381     rprintfProgStrM("Calculating filesystem parameters\r\n");
00382     // clear sector buffer
00383     memset(SectorBuffer, 0, 512);
00384     // create boot sector and bios parameter block
00385     bs = (struct bootsector710 *)SectorBuffer;
00386 
00387     strcpy(&bs->bsOEMName[0], "MSDOS5.0");
00388     
00389     bpb = (struct bpb710*)bs->bsBPB;
00390 
00391     // BPB for FAT16
00392     bpb->bpbBytesPerSec = 0x200;    // standard 512Kbyte sectors
00393     bpb->bpbSecPerClust = 8;        // standard 4K clusters
00394     bpb->bpbResSectors = 4;         // number of reserved sectors before FAT starts
00395     bpb->bpbFATs = 2;               // standard 2 FATs
00396     bpb->bpbRootDirEnts = 0x200;    // 512 entries
00397     if(volsize < 0x10000)
00398     {
00399         // can be FAT16 only
00400         bpb->bpbSectors = volsize;  // size of the volume in sectors
00401         bpb->bpbHugeSectors = 0;    
00402     }
00403     else
00404     {
00405         // can be FAT16 or FAT32
00406         bpb->bpbSectors = 0;
00407         bpb->bpbHugeSectors = volsize;  // size of the volume in sectors
00408     }
00409     // -----------------------------------------------------------------
00410     // figure out how to split the drive into FAT(s) and data clusters
00411     // -determine the number of sectors usable for FAT and clusters
00412     i = volsize - (bpb->bpbResSectors + (bpb->bpbRootDirEnts+(DIRENTRIES_PER_SECTOR-1))/DIRENTRIES_PER_SECTOR);
00413     // -each cluster occupies bpbSecPerClust + 1 FAT entry (2/4 bytes) per fat
00414     j = ((unsigned short)bpb->bpbSecPerClust<<8) + bpb->bpbFATs;
00415     // if fat32 then j/=2;
00416     fatsecs = (i+(j-1))/j;
00417     /*
00418     rprintf("rootentr = "); rprintfu32(bpb->bpbRootDirEnts); rprintfCRLF();
00419     rprintf("i = "); rprintfu32(i); rprintfCRLF();
00420     rprintf("j = "); rprintfu32(j); rprintfCRLF();
00421     rprintf("fatsecs = %d\r\n", fatsecs);
00422     */
00423     // -----------------------------------------------------------------    
00424     if(fatsecs < 65525)
00425     {
00426         // FAT16
00427         bpb->bpbFATsecs = fatsecs;  // number of sectors per FAT
00428     }
00429     else
00430     {
00431         // FAT32
00432         bpb->bpbFATsecs = 0;            // real value is in bigFatSecs
00433         bpb->bpbBigFATsecs = fatsecs;   // number of sectors per FAT
00434     }
00435     bpb->bpbMedia = 0xF8;           // 0xF8 = standard fixed disk
00436     bpb->bpbSecPerTrack = 63;   
00437     bpb->bpbHeads = 255;
00438     bpb->bpbHiddenSecs = 0;
00439     // BPB for FAT32
00440     bpb->bpbExtFlags = 0;           // FATs are mirrored
00441     bpb->bpbFSVers = FSVERS;
00442 
00443     // apply bootsector signature
00444     bs->bsBootSectSig0 = 0x55;
00445     bs->bsBootSectSig1 = 0xAA;
00446 
00447     // write bootsector
00448     rprintfProgStrM("Writing boot sector\r\n");
00449     FatFsInfo.devdisk.WriteSector(0, 1, SectorBuffer);
00450 
00451     // SECOND STAGE
00452     // initialize the FAT(s) and create the root directory
00453 
00454     // "remount" the filesystem
00455     rprintfProgStrM("Remounting Filesystem...\r\n");
00456     fatInit(&FatFsInfo.devdisk);
00457     // clear sector buffer
00458     memset(SectorBuffer, 0, 512);
00459     // initialize the FATs
00460     rprintfProgStrM("Initializing FAT sectors...\r\n");
00461     for(i=0; i<(FatFsInfo.NumberOfFats*FatFsInfo.SectorsPerFat); i++)
00462     {
00463         rprintfProgStrM("Writing FAT sector: "); rprintfu32(FatFsInfo.FirstFATSector+i); rprintfChar('\r');
00464         FatFsInfo.devdisk.WriteSector(FatFsInfo.FirstFATSector+i, 1, SectorBuffer);
00465     }
00466     rprintfCRLF();
00467 
00468     // create the root directory
00469     rprintfProgStrM("Creating Root Directory...\r\n");
00470     // tag root directory cluster as used in FAT
00471     fatWriteClusterValue(FatFsInfo.RootDirStartCluster, CLUST_EOFE);
00472     // find the starting sector of the root directory
00473     sector = fatClusterToSector(FatFsInfo.RootDirStartCluster);
00474     // clear sector buffer
00475     memset(SectorBuffer, 0, 512);
00476     // clear the cluster where the root directory will reside
00477     for(i=0; i<FatFsInfo.SectorsPerCluster; i++)
00478     {
00479         rprintfProgStrM("Writing Root Dir sector: "); rprintfu32(sector+i); rprintfChar('\r');
00480         FatFsInfo.devdisk.WriteSector(sector+i, 1, SectorBuffer);
00481     }
00482     rprintfCRLF();
00483 
00484     // create volume label entry
00485     rprintfProgStrM("Creating Volume Label...\r\n");
00486     
00487     FileInfo.Attr = ATTR_VOLUME;
00488     FileInfo.Size = 0;
00489     FileInfo.StartCluster = 0;
00490     FileInfo.CreateDate = 0;
00491     FileInfo.CreateTime = 0;
00492 
00493     fatCreateFile("MYDISK", &FileInfo);
00494 
00495     return 0;
00496 }
00497 
00498 // change directory into 
00499 unsigned char fatChangeDirectory(unsigned short entry)
00500 {
00501     // get the requested directory entry
00502     if( fatGetDirEntry(entry) )
00503     {
00504         // make sure the entry is a directory
00505         if(FileInfo.Attr & ATTR_DIRECTORY)
00506         {
00507             // change directories into this directory
00508             // check to see if we are changing back to root directory
00509             if(FileInfo.StartCluster)
00510             {
00511                 // standard change directory
00512                 CurrentDirStartCluster = FileInfo.StartCluster;
00513             }
00514             else
00515             {
00516                 // if startCluster pointer is zero,
00517                 // a change to the root directory is intended
00518                 // change directory to root
00519                 CurrentDirStartCluster = FatFsInfo.RootDirStartCluster;
00520             }
00521             // TODO: handle pathname properly for going up a directory
00522             // set path string
00523             strcat(PathNameBuffer, FileNameBuffer);
00524             strcat(PathNameBuffer, "\\");
00525             // return success
00526             return TRUE;
00527         }
00528         else
00529         {
00530             // not a directory, cannot CD into a file!
00531             return FALSE;
00532         }
00533     }
00534     else
00535     {
00536         // not a valid entry, cannot CD!
00537         return FALSE;
00538     }
00539 }
00540 
00541 void fatPrintDirEntry(void)
00542 {
00543     // print a formatted dir-style output for most recent file
00544     // print date
00545     rprintfNum(10, 2, FALSE, '0', (FileInfo.CreateDate&DD_MONTH_MASK)>>DD_MONTH_SHIFT );    // month
00546     rprintfChar('/');
00547     rprintfNum(10, 2, FALSE, '0', (FileInfo.CreateDate&DD_DAY_MASK)>>DD_DAY_SHIFT );        // day
00548     rprintfChar('/');
00549     rprintfNum(10, 4, FALSE, '0', (FileInfo.CreateDate&DD_YEAR_MASK)>>DD_YEAR_SHIFT );  // year
00550     rprintfChar(' ');
00551 
00552     // print time
00553     rprintfNum(10, 2, FALSE, '0', (FileInfo.CreateTime&DT_HOURS_MASK)>>DT_HOURS_SHIFT );    // month
00554     rprintfChar(':');
00555     rprintfNum(10, 2, FALSE, '0', (FileInfo.CreateTime&DT_MINUTES_MASK)>>DT_MINUTES_SHIFT );        // day
00556     rprintfChar(':');
00557     rprintfNum(10, 2, FALSE, '0', 2*(FileInfo.CreateTime&DT_2SECONDS_MASK)>>DT_2SECONDS_SHIFT );    // seconds
00558     rprintfChar(' ');
00559 
00560     // print attributes
00561     if(FileInfo.Attr & ATTR_VOLUME)     rprintfChar('V'); else rprintfChar('-');
00562     if(FileInfo.Attr & ATTR_DIRECTORY)  rprintfChar('D'); else rprintfChar('-');
00563     if(FileInfo.Attr & ATTR_READONLY)   rprintfChar('R'); else rprintfChar('-');
00564     if(FileInfo.Attr & ATTR_HIDDEN)     rprintfChar('H'); else rprintfChar('-');
00565     if(FileInfo.Attr & ATTR_SYSTEM)     rprintfChar('S'); else rprintfChar('-');
00566     if(FileInfo.Attr & ATTR_ARCHIVE)    rprintfChar('A'); else rprintfChar('-');
00567     rprintfChar(' ');
00568 
00569     // print filesize
00570     rprintfNum(10, 8, FALSE, ' ', FileInfo.Size);   // filesize
00571     rprintfChar(' ');
00572 
00573     // print filename
00574     rprintfStr(FileNameBuffer);
00575 }
00576 
00577 void fatDumpDirSlot(unsigned short slot)
00578 {
00579     unsigned long sector;
00580     
00581     // load correct sector
00582     sector = fatClusterToSector(CurrentDirStartCluster);
00583     sector += slot/DIRENTRIES_PER_SECTOR;
00584 
00585     rprintf("CurrentDirStartCluster:");
00586     rprintfu32(CurrentDirStartCluster);
00587     rprintfCRLF();
00588     rprintf("Sector access         :");
00589     rprintfu32(sector);
00590     rprintfCRLF();
00591         
00592     // print the entry as a hex table
00593     debugPrintHexTable(32, SectorBuffer+(slot<<5) );
00594 }
00595 
00596 FileInfo_t* fatGetFileInfo(void)
00597 {
00598     return &FileInfo;
00599 }
00600 
00601 // return the size of the last directory entry
00602 unsigned long fatGetFilesize(void)
00603 {
00604     return FileInfo.Size;
00605 }
00606 
00607 // return the long name of the last directory entry
00608 char* fatGetFilename(void)
00609 {   
00610     return FileNameBuffer;
00611 }
00612 
00613 // return the directory of the last directory entry
00614 char* fatGetDirname(void)
00615 {   
00616     return PathNameBuffer;
00617 }
00618 
00619 // load a cluster-full of data
00620 void fatLoadCluster(unsigned long cluster, unsigned char *buffer)
00621 {
00622     register unsigned char i;
00623     // read cluster
00624     //while ( ataReadSectors( FatFsInfo.disk, clust2sect(cluster), SectorsPerCluster, buffer) != 0);
00625     for(i=0; i<FatFsInfo.SectorsPerCluster; i++)
00626     {
00627         FatFsInfo.devdisk.ReadSector(fatClusterToSector(cluster)+i, 1, buffer+(i<<9) );
00628         // temporary fix for wierd misaligned cluster problem
00629         // (only when using FAT16?)
00630 //      ataReadSectors(FatFsInfo.disk, fatClustToSect(cluster+8)+i, 1, buffer+(i<<9) );
00631     }
00632 }
00633 
00634 
00635 // find next cluster in the FAT chain
00636 unsigned long fatNextCluster(unsigned long cluster)
00637 {
00638     unsigned long nextCluster;
00639 
00640     // read the nextCluster value
00641     nextCluster = fatClusterValue(cluster);
00642 
00643     // check to see if we're at the end of the chain
00644     if (nextCluster == (CLUST_EOFE & FatFsInfo.FatMask))
00645         nextCluster = 0;
00646 
00647 #ifdef DEBUG_FAT
00648     rprintfProgStrM(">");
00649     rprintfu32(nextCluster);
00650     rprintfCRLF();
00651 #endif
00652     
00653     return nextCluster;
00654 }
00655 
00656 unsigned long fatNextFreeCluster(void)
00657 {
00658     unsigned long cluster;
00659 
00660     // start at beginning of fat
00661     cluster = FatFsInfo.RootDirStartCluster;
00662 
00663     while( fatClusterValue(cluster) != CLUST_FREE)
00664     {
00665         // increment to next cluster
00666         cluster++;
00667     }
00668     return cluster;
00669 }
00670 
00671 unsigned long fatClusterValue(unsigned long cluster)
00672 {
00673     // return the value of the FAT entry for the requested cluster
00674     unsigned char* buffer;
00675     unsigned long fatOffset;
00676     unsigned long sector;
00677     unsigned int offset;
00678     
00679     // get fat offset in bytes
00680     if(FatFsInfo.Fat32Enabled)
00681     {
00682         // four FAT bytes (32 bits) for every cluster
00683         fatOffset = cluster << 2;
00684     }
00685     else
00686     {
00687         // two FAT bytes (16 bits) for every cluster
00688         fatOffset = cluster << 1;
00689     }
00690     
00691     // calculate the FAT sector that we're interested in
00692     sector = (fatOffset / FatFsInfo.BytesPerSector);
00693     // calculate offset of the our entry within that FAT sector
00694     offset = fatOffset % FatFsInfo.BytesPerSector;
00695     // get the fat sector
00696     buffer = fatGetFatSector( sector );
00697     // return the fat value of the cluster
00698     // NOTE: don't be fooled by the UNSIGNED LONG,
00699     // this should nominally work for both FAT16 and FAT32
00700     // FAT16 -> offset will be on 2-byte boundary
00701     // FAT32 -> offset will be on 4-byte boundary
00702     return (*((unsigned long*) &buffer[offset])) & FatFsInfo.FatMask;
00703 }
00704 
00705 int fatWriteClusterValue(unsigned long cluster, unsigned value)
00706 {
00707     // write the value of the FAT entry for the requested cluster
00708     unsigned char* buffer;
00709     unsigned long fatOffset;
00710     unsigned long fatSector;
00711     unsigned int offset;
00712     
00713     // get fat offset in bytes
00714     if(FatFsInfo.Fat32Enabled)
00715     {
00716         // four FAT bytes (32 bits) for every cluster
00717         fatOffset = cluster << 2;
00718     }
00719     else
00720     {
00721         // two FAT bytes (16 bits) for every cluster
00722         fatOffset = cluster << 1;
00723     }
00724     
00725     // calculate the FAT sector that we're interested in
00726     fatSector = (fatOffset / FatFsInfo.BytesPerSector);
00727     // calculate offset of the our entry within that FAT sector
00728     offset = fatOffset % FatFsInfo.BytesPerSector;
00729     // get the fat sector
00730     buffer = fatGetFatSector( fatSector );
00731     // write the fat value of the cluster
00732     // NOTE: don't be fooled by the UNSIGNED LONG,
00733     // this should nominally work for both FAT16 and FAT32
00734     // FAT16 -> offset will be on 2-byte boundary
00735     // FAT32 -> offset will be on 4-byte boundary
00736     *((unsigned long*) &buffer[offset]) = (value & FatFsInfo.FatMask);
00737 
00738     // flush to disk
00739     FatFsInfo.devdisk.WriteSector(FatFsInfo.FirstFATSector+fatSector, 1, buffer);
00740 
00741     return 0;
00742 }
00743 
00744 unsigned char* fatGetFatSector(unsigned long fatsector)
00745 {
00746     // NOTE: fatsector is referenced to the beginning of the fat
00747     // eg. fatsector=0 is the first sector of the first FAT
00748 
00749     // the idea here is to make a generic FAT loading function that
00750     // can later be used to cache not one but multiple FAT sectors that
00751     // have been recently used
00752 
00753     // if we don't already have this FAT chunk loaded, go get it
00754     if(fatsector != FatFsInfo.FatInCache)
00755     {
00756         // read sector of FAT table
00757         while (FatFsInfo.devdisk.ReadSector(FatFsInfo.FirstFATSector+fatsector, 1, FatCacheBuffer) != 0);
00758         FatFsInfo.FatInCache = fatsector;
00759     }
00760     return FatCacheBuffer;
00761 }
00762 
00763 unsigned long fatClusterToSector(unsigned long cluster)
00764 {
00765     return ((cluster-2) * FatFsInfo.SectorsPerCluster) + FatFsInfo.FirstDataSector;
00766 }
00767 
00768 unsigned int fatClusterSize(void)
00769 {
00770     // return the number of sectors in a disk cluster
00771     return FatFsInfo.SectorsPerCluster;
00772 }

Generated on Mon Nov 6 23:36:59 2006 for Procyon ARMlib by  doxygen 1.4.2