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 }