Nut/OS  4.10.3
API Reference
fat.c
Go to the documentation of this file.
00001 /****************************************************************************
00002 *  This file is part of the AVRIDE device driver.
00003 *
00004 *  Copyright (c) 2002-2003 by Michael Fischer. All rights reserved.
00005 *
00006 *  Redistribution and use in source and binary forms, with or without 
00007 *  modification, are permitted provided that the following conditions 
00008 *  are met:
00009 *  
00010 *  1. Redistributions of source code must retain the above copyright 
00011 *     notice, this list of conditions and the following disclaimer.
00012 *  2. Redistributions in binary form must reproduce the above copyright
00013 *     notice, this list of conditions and the following disclaimer in the 
00014 *     documentation and/or other materials provided with the distribution.
00015 *  3. Neither the name of the author nor the names of its contributors may 
00016 *     be used to endorse or promote products derived from this software 
00017 *     without specific prior written permission.
00018 *
00019 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
00020 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
00021 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
00022 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
00023 *  THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
00024 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
00025 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 
00026 *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
00027 *  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
00028 *  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
00029 *  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
00030 *  SUCH DAMAGE.
00031 *
00032 ****************************************************************************
00033 *  History:
00034 *
00035 *  14.12.02  mifi   First Version 
00036 *  23.12.02  mifi   Add FileOpen, FileClose, FileError, FileSize,
00037 *                   FileSeek and FileRead. But the FileSeek function.
00038 *                   does not work in the moment, later...
00039 *  28.12.02  mifi   Now support FAT16 AND FAT32.
00040 *  01.01.03  mifi   Support long directory entries, but without to 
00041 *                   check the checksum of the short entry.
00042 *                   Change FAT32FileSize return value from int to long.
00043 *                   The max size of a long filename segment is
00044 *                   (FAT_LONG_NAME_LEN-1). But the complete filename can
00045 *                   be longer. 
00046 *
00047 *                   segment1/segment2/segment3/index.html
00048 *
00049 *                   segmentX max length = (FAT_LONG_NAME_LEN-1)
00050 *
00051 *  04.01.03  mifi   Take a look at the return values...
00052 *  18.01.03  mifi   Change Licence from GPL to BSD.
00053 *  25.01.03  mifi   Implement a new FindFile function.
00054 *                   I have some trouble with short file names under
00055 *                   Win98. Win98 store a short name like "enlogo.gif"
00056 *                   as a long name, nasty OS. 
00057 *                   Remove FAT32_MAX_FILES and the array aFileHandle,
00058 *                   a file handle will now be allocated by NutHeapAlloc, 
00059 *                   therefore we have no restrictions about the count of 
00060 *                   the open file handle. (Only by available memory)
00061 *  27.01.03  mifi   Rename all FAT32xxx function to FATxxx.
00062 *
00063 *  28.01.03  mifi   Start porting to Nut/OS 3.X.X
00064 *  19.06.03  mifi   Change the call of IDEInit, now we use the BaseAddress
00065 *                   of 0. Because the fat module does not need to know the
00066 *                   address. It will be handled in ide.c.
00067 *  29.06.03  mifi   First ATAPI-Version
00068 *                   Now we can read files from a CD-ROM. But there exist
00069 *                   some open points:
00070 *                   - only first session from a multisession CD is supported
00071 *                   - only iso9660, no Joliet support now, later
00072 ****************************************************************************/
00073 #define __FAT_C__
00074 
00075 #include <string.h>
00076 #include <stddef.h>
00077 #include <ctype.h>
00078 
00079 #include <sys/heap.h>
00080 #include <sys/event.h>
00081 #include <sys/thread.h>
00082 
00083 #include <sys/device.h>
00084 
00085 #include <dev/ide.h>
00086 #include <fs/fat.h>
00087 #include <fs/typedefs.h>
00088 
00089 /*==========================================================*/
00090 /*  DEFINE: All Structures and Common Constants             */
00091 /*==========================================================*/
00092 //
00093 // FAT return codes
00094 //
00095 #define FAT_OK                0
00096 #define FAT_ERROR             -1
00097 #define FAT_ERROR_EOF         -2
00098 #define FAT_ERROR_IDE         -3
00099 
00100 //
00101 // Define for correct return values Nut/OS
00102 //
00103 #define NUTDEV_OK                       0
00104 #define NUTDEV_ERROR                    -1
00105 
00106 
00107 #define FAT_MAX_DRIVE                   2
00108 
00109 //
00110 // Some defines for the FAT structures
00111 //
00112 #define ZIP_DRIVE_BR_SECTOR             32
00113 
00114 #define BPB_RsvdSecCnt                  32
00115 #define BPB_NumFATs                     2
00116 #define BPB_HiddSec                     63
00117 
00118 #define FAT32_MEDIA                     0xf8
00119 
00120 #define FAT32_OFFSET_FSINFO             1
00121 #define FAT32_OFFSET_BACKUP_BOOT        6
00122 
00123 #define FAT16_CLUSTER_EOF               0x0000FFFF
00124 #define FAT16_CLUSTER_ERROR             0x0000FFF7
00125 #define FAT16_CLUSTER_MASK              0x0000FFFF
00126 
00127 #define FAT32_CLUSTER_EOF               0x0FFFFFFF
00128 #define FAT32_CLUSTER_ERROR             0x0FFFFFF7
00129 #define FAT32_CLUSTER_MASK              0x0FFFFFFF
00130 
00131 #define FAT_SIGNATURE                   0xAA55
00132 
00133 #define MBR_SIGNATURE                   FAT_SIGNATURE
00134 #define MBR_FAT32                       0x0C
00135 
00136 #define FSINFO_FIRSTSIGNATURE           0x41615252
00137 #define FSINFO_FSINFOSIGNATURE          0x61417272
00138 #define FSINFO_SIGNATURE                FAT_SIGNATURE
00139 
00140 #define DIRECTORY_ATTRIBUTE_READ_ONLY   0x01
00141 #define DIRECTORY_ATTRIBUTE_HIDDEN      0x02
00142 #define DIRECTORY_ATTRIBUTE_SYSTEM_FILE 0x04
00143 #define DIRECTORY_ATTRIBUTE_VOLUME_ID   0x08
00144 #define DIRECTORY_ATTRIBUTE_DIRECTORY   0x10
00145 #define DIRECTORY_ATTRIBUTE_ARCHIVE     0x20
00146 
00147 //
00148 // DIRECTORY_ATTRIBUTE_READ_ONLY   |
00149 // DIRECTORY_ATTRIBUTE_HIDDEN      |
00150 // DIRECTORY_ATTRIBUTE_SYSTEM_FILE |
00151 // DIRECTORY_ATTRIBUTE_VOLUME_ID
00152 //
00153 #define DIRECTORY_ATTRIBUTE_LONG_NAME   0x0F
00154 
00155 //
00156 // DIRECTORY_ATTRIBUTE_READ_ONLY   |
00157 // DIRECTORY_ATTRIBUTE_HIDDEN      |
00158 // DIRECTORY_ATTRIBUTE_SYSTEM_FILE |
00159 // DIRECTORY_ATTRIBUTE_VOLUME_ID   |
00160 // DIRECTORY_ATTRIBUTE_DIRECTORY   |
00161 // DIRECTORY_ATTRIBUTE_ARCHIVE
00162 // 
00163 #define DIRECTORY_ATTRIBUTE_LONG_NAME_MASK  0x3F
00164 
00165 #define FAT_NAME_LEN                    8
00166 #define FAT_EXT_LEN                     3
00167 
00168 //
00169 // FAT_SHORT_NAME_LEN name len = 
00170 // name + ext + 1 for the point
00171 //
00172 #define FAT_SHORT_NAME_LEN              (FAT_NAME_LEN+FAT_EXT_LEN+1)
00173 #define FAT_LONG_NAME_LEN               64
00174 
00175 
00176 //
00177 // Some stuff for HD and CD, DRIVE_INFO Flags
00178 // 
00179 //
00180 #define FLAG_FAT_IS_CDROM               0x0001
00181 #define FLAG_FAT_IS_ZIP                 0x0002
00182 
00183 //
00184 //  DiskSize to SectorPerCluster table
00185 //
00186 typedef struct {
00187     DWORD DiskSize;
00188     BYTE SecPerClusVal;
00189 } DSKSZTOSECPERCLUS;
00190 
00191 typedef struct _FAT32FileDataTime {
00192     unsigned Seconds:5;
00193     unsigned Minute:6;
00194     unsigned Hour:5;
00195     unsigned Day:5;
00196     unsigned Month:4;
00197     unsigned Year:7;
00198 } FAT32_FILEDATETIME, *PFAT32_FILEDATETIME;
00199 
00200 typedef struct _FAT32DirectoryEntry {
00201     BYTE Name[FAT_NAME_LEN];
00202     BYTE Extension[FAT_EXT_LEN];
00203     BYTE Attribute;
00204     BYTE Reserved[8];
00205     WORD HighCluster;
00206     FAT32_FILEDATETIME Date;
00207     WORD LowCluster;
00208     DWORD FileSize;
00209 } FAT32_DIRECTORY_ENTRY;
00210 
00211 typedef struct _FAT32DirectoryEntryLong {
00212     BYTE Order;
00213     WORD Name1[5];
00214     BYTE Attribute;
00215     BYTE Type;
00216     BYTE Chksum;
00217     WORD Name2[6];
00218     WORD LowCluster;
00219     WORD Name3[2];
00220 } FAT32_DIRECTORY_ENTRY_LONG;
00221 
00222 typedef struct _FAT32FileSystemInformation {
00223     DWORD FirstSignature;
00224     BYTE Reserved1[480];
00225     DWORD FSInfoSignature;
00226     DWORD NumberOfFreeClusters;
00227     DWORD MostRecentlyAllocatedCluster;
00228     BYTE Reserved2[12];
00229     BYTE Reserved3[2];
00230     WORD Signature;
00231 } FAT32_FSINFO;
00232 
00233 typedef struct _FAT32PartitionEntry {
00234     BYTE BootInd;
00235     BYTE FirstHead;
00236     BYTE FirstSector;
00237     BYTE FirstTrack;
00238     BYTE FileSystem;
00239     BYTE LastHead;
00240     BYTE LastSector;
00241     BYTE LastTrack;
00242     DWORD StartSectors;
00243     DWORD NumSectors;
00244 } FAT32_PARTITION_ENTRY;
00245 
00246 typedef struct _FAT32PartionTable {
00247     BYTE LoadInstruction[446];
00248     FAT32_PARTITION_ENTRY Partition[4];
00249     WORD Signature;             /* AA55 */
00250 } FAT32_PARTITION_TABLE;
00251 
00252 typedef struct _bpbfat16 {
00253     BYTE DrvNum;
00254     BYTE Reserved1;
00255     BYTE BootSig;
00256     DWORD VollID;
00257     BYTE VolLab[11];
00258     BYTE FilSysType[8];
00259     BYTE Reserved2[28];
00260 } BPBFAT16;
00261 
00262 typedef struct _bpbfat32 {
00263     DWORD FATSz32;              // xxx
00264     WORD ExtFlags;              // 0
00265     WORD FSVer;                 // must 0
00266     DWORD RootClus;             // 
00267     WORD FSInfo;                // typically 1
00268     WORD BkBootSec;             // typically 6
00269     BYTE Reserved[12];          // set all to zero
00270     BYTE DrvNum;                // must 0x80
00271     BYTE Reserved1;             // set all to zero
00272     BYTE BootSig;               // must 0x29 
00273     DWORD VollID;               // xxx
00274     BYTE VolLab[11];            // "abcdefghijk"
00275     BYTE FilSysType[8];         // "FAT32   "
00276 } BPBFAT32;
00277 
00278 typedef union _bpboffset36 {
00279     BPBFAT16 FAT16;
00280     BPBFAT32 FAT32;
00281 } BPBOFFSET36;
00282 
00283 typedef struct _FAT32BootRecord {
00284     BYTE JumpBoot[3];           // 0xeb, 0x58, 0x90
00285     BYTE OEMName[8];            // "MSWIN4.1"
00286     WORD BytsPerSec;            // must 512
00287     BYTE SecPerClus;            // 8 for 4K cluster
00288     WORD RsvdSecCnt;            // typically 32 for FAT32
00289     BYTE NumFATs;               // always 2
00290     WORD RootEntCnt;            // must 0 for FAT32
00291     WORD TotSec16;              // must 0 for FAT32
00292     BYTE Media;                 // must 0xf8
00293 
00294     WORD FATSz16;               // 0   for FAT32
00295     WORD SecPerTrk;             // 63  for FAT32
00296     WORD NumHeads;              // 255 for FAT32
00297     DWORD HiddSec;              // 63  for FAT32
00298 
00299     DWORD TotSec32;             // xxx
00300 
00301     BPBOFFSET36 Off36;
00302 
00303     BYTE Reserved[420];
00304     WORD Signature;             // must 0xAA55
00305 } FAT32_BOOT_RECORD, *PFAT32_BOOT_RECORD;
00306 
00307 typedef struct _fat_entry_table16 {
00308     WORD aEntry[256];
00309 } FAT_ENTRY_TABLE16;
00310 
00311 typedef struct _fat_entry_table32 {
00312     DWORD aEntry[128];
00313 } FAT_ENTRY_TABLE32;
00314 
00315 typedef union _fat_dir_table {
00316     FAT32_DIRECTORY_ENTRY aShort[16];
00317     FAT32_DIRECTORY_ENTRY_LONG aLong[16];
00318 } FAT_DIR_TABLE;
00319 
00320 typedef struct _drive_info {
00321     BYTE bIsFAT32;
00322     BYTE bDevice;
00323     BYTE bSectorsPerCluster;
00324     BYTE bFlags;
00325 
00326     WORD wSectorSize;
00327 
00328     DWORD dwRootDirSectors;
00329     DWORD dwFirstRootDirSector;
00330 
00331     DWORD dwRootCluster;
00332     DWORD dwFAT1StartSector;
00333     DWORD dwFAT2StartSector;
00334     DWORD dwCluster2StartSector;
00335 
00336     DWORD dwClusterSize;
00337 } DRIVE_INFO;
00338 
00339 typedef struct _fhandle {
00340     DWORD dwFileSize;
00341     DWORD dwStartCluster;
00342     DWORD dwReadCluster;
00343     DWORD dwFilePointer;        /* total file pointer   */
00344     DWORD dwClusterPointer;     /* cluster read pointer */
00345 
00346     int nLastError;
00347     int nEOF;
00348 
00349     DRIVE_INFO *pDrive;
00350 } FHANDLE;
00351 
00352 #if (IDE_SUPPORT_ATAPI == 1)
00353 //
00354 // Some ATAPI stuff
00355 //
00356 typedef struct _atapi_pvd {
00357     BYTE descr_type;
00358     BYTE magic[5];
00359     BYTE descr_ver;
00360     BYTE unused;
00361     BYTE sysid[32];
00362     BYTE volid[32];
00363     BYTE zeros1[8];
00364     BYTE seknum[8];
00365     BYTE zeros2[32];
00366     BYTE volsetsize[4];
00367     BYTE volseqnum[4];
00368     BYTE seksize[4];
00369     BYTE pathtablen[8];
00370     DWORD firstsek_LEpathtab1_LE;
00371     DWORD firstsek_LEpathtab2_LE;
00372     BYTE firstsek_BEpathtab1_BE[4];
00373     BYTE firstsek_BEpathtab2_BE[4];
00374     BYTE rootdir[34];
00375     BYTE volsetid[128];
00376     BYTE pubid[128];
00377     BYTE dataprepid[128];
00378     BYTE appid[128];
00379     BYTE copyr[37];
00380     BYTE abstractfileid[37];
00381     BYTE bibliofileid[37];
00382     BYTE creationdate[17];
00383     BYTE modify[17];
00384     BYTE expire[17];
00385     BYTE effective[17];
00386     BYTE filestruc_ver;
00387     BYTE zero;
00388     BYTE app_use[512];
00389     BYTE res[653];
00390 } ATAPI_PVD;
00391 
00392 //
00393 // Descriptor values
00394 //
00395 #define ATAPI_BOOT_RECORD   0x00
00396 #define ATAPI_PVD_DESC      0x01
00397 #define ATAPI_SVD_DESC      0x02
00398 #define ATAPI_VDST_DESC     0xFF
00399 
00400 typedef struct _ATAPIDirectoryRecord {
00401     BYTE bRecordSize;
00402     BYTE bShouldBeZero;
00403     DWORD dwFirstSector;
00404     DWORD dwNotUse1;
00405     DWORD dwEntrySize;
00406     DWORD dwNotUse2;
00407     BYTE bDate[7];
00408     BYTE bFlags;
00409     BYTE bInterleaveInfo[2];
00410     BYTE bVolumeSequenceNumber[4];
00411     BYTE bIdentifierLength;
00412     BYTE bName[1];
00413 } ATAPI2_DIRECTORY_RECORD;
00414 #endif
00415 
00416 /*==========================================================*/
00417 /*  DEFINE: Definition of all local Data                    */
00418 /*==========================================================*/
00419 static int gnIsInit = FALSE;
00420 
00421 static BYTE *pSectorBuffer = NULL;
00422 static char *pLongName1 = NULL;
00423 static char *pLongName2 = NULL;
00424 static DRIVE_INFO sDriveInfo[FAT_MAX_DRIVE];
00425 
00426 static HANDLE hFATSemaphore;
00427 /*==========================================================*/
00428 /*  DEFINE: Definition of all local Procedures              */
00429 /*==========================================================*/
00430 /************************************************************/
00431 /*  FATLock                                                 */
00432 /************************************************************/
00433 void FATLock(void)
00434 {
00435     NutEventWait(&hFATSemaphore, 0);
00436 }
00437 
00438 /************************************************************/
00439 /*  FATFree                                                 */
00440 /************************************************************/
00441 void FATFree(void)
00442 {
00443     NutEventPost(&hFATSemaphore);
00444 }
00445 
00446 /************************************************************/
00447 /*  FATSemaInit                                             */
00448 /************************************************************/
00449 void FATSemaInit(void)
00450 {
00451     NutEventPost(&hFATSemaphore);
00452 }
00453 
00454 /************************************************************/
00455 /*  GetFirstSectorOfCluster                                 */
00456 /************************************************************/
00457 static DWORD GetFirstSectorOfCluster(DRIVE_INFO * pDrive, DWORD dwCluster)
00458 {
00459     DWORD dwSector;
00460 
00461     if (pDrive->bFlags & FLAG_FAT_IS_CDROM) {
00462         dwSector = dwCluster;
00463     } else {
00464         dwSector = (dwCluster - 2) * pDrive->bSectorsPerCluster;
00465         dwSector += pDrive->dwCluster2StartSector;
00466     }
00467 
00468     return (dwSector);
00469 }
00470 
00471 /************************************************************/
00472 /*  GetNextCluster                                          */
00473 /************************************************************/
00474 static DWORD GetNextCluster(DRIVE_INFO * pDrive, DWORD dwCluster)
00475 {
00476     DWORD dwNextCluster;
00477     DWORD dwSector;
00478     DWORD dwIndex;
00479     FAT_ENTRY_TABLE16 *pFatTable16;
00480     FAT_ENTRY_TABLE32 *pFatTable32;
00481 
00482     if (pDrive->bFlags & FLAG_FAT_IS_CDROM) {
00483         dwNextCluster = dwCluster + 1;
00484     } else {
00485         if (pDrive->bIsFAT32 == TRUE) {
00486             //
00487             //  (IDE_SECTOR_SIZE / sizeof(long)) == 128
00488             // 
00489             dwSector = (dwCluster / 128) + pDrive->dwFAT1StartSector;
00490             dwIndex = dwCluster % 128;
00491 
00492             IDEReadSectors(pDrive->bDevice, pSectorBuffer, dwSector, 1);
00493             pFatTable32 = (FAT_ENTRY_TABLE32 *) pSectorBuffer;
00494 
00495             dwNextCluster = (pFatTable32->aEntry[dwIndex] & FAT32_CLUSTER_MASK);
00496             if ((dwNextCluster == FAT32_CLUSTER_EOF) || (dwNextCluster == FAT32_CLUSTER_ERROR)) {
00497                 dwNextCluster = 0;
00498             }
00499 
00500         } else {                /* FAT16 */
00501             //
00502             //  (IDE_SECTOR_SIZE / sizeof(word)) == 256
00503             // 
00504             dwSector = (dwCluster / 256) + pDrive->dwFAT1StartSector;
00505             dwIndex = dwCluster % 256;
00506 
00507             IDEReadSectors(pDrive->bDevice, pSectorBuffer, dwSector, 1);
00508             pFatTable16 = (FAT_ENTRY_TABLE16 *) pSectorBuffer;
00509 
00510             dwNextCluster = (pFatTable16->aEntry[dwIndex] & FAT16_CLUSTER_MASK);
00511             if ((dwNextCluster == FAT16_CLUSTER_EOF) || (dwNextCluster == FAT16_CLUSTER_ERROR)) {
00512                 dwNextCluster = 0;
00513             }
00514 
00515         }                       /* endif pDrive->bIsFAT32 */
00516     }
00517 
00518     return (dwNextCluster);
00519 }
00520 
00521 /************************************************************/
00522 /*  GetLongChar                                             */
00523 /************************************************************/
00524 static char GetLongChar(WORD wValue)
00525 {
00526     BYTE Value;
00527 
00528     Value = (BYTE) (wValue & 0x00FF);
00529     if (Value == 0xFF) {
00530         Value = 0;
00531     }
00532 
00533     if (Value != 0) {
00534         Value = toupper(Value);
00535     }
00536 
00537     return ((char) Value);
00538 }
00539 
00540 #if (IDE_SUPPORT_ATAPI == 1)
00541 /************************************************************/
00542 /*  CheckATAPIName                                          */
00543 /*                                                          */
00544 /*  Some values are not allowed in a "ATAPIname",           */
00545 /*  Therefore we will change the name here.                 */
00546 /************************************************************/
00547 static char *CheckATAPIName(char *pLongName)
00548 {
00549     char *pRead;
00550 
00551     pRead = pLongName;
00552 
00553     while (*pRead != 0) {
00554         switch (*pRead) {
00555         case '-':
00556             *pRead = '_';
00557             break;
00558         case ' ':
00559             *pRead = '_';
00560             break;
00561         }
00562         pRead++;
00563     }
00564 
00565     return (pLongName);
00566 }
00567 
00568 /************************************************************/
00569 /*  RemoveChar                                              */
00570 /*                                                          */
00571 /*  Houston, we have a problem....                          */
00572 /*  Some chars are not allowed in a name, in the case of    */
00573 /*  ATAPI, the filename test.pic.gif is stored as           */
00574 /*  testpic.gif. For a directory, we must remove all '.'    */
00575 /*  Therefore we must correct the name :o(                  */
00576 /************************************************************/
00577 static char *RemoveChar(char *pLongName, BYTE bDir)
00578 {
00579     char *pRead;
00580     char *pWrite;
00581     BYTE bPointCount;
00582 
00583     pRead = pLongName;
00584     pWrite = pLongName;
00585 
00586     if (bDir == TRUE) {
00587         while (*pRead != 0) {
00588             if (*pRead != '.') {
00589                 *pWrite = *pRead;
00590                 pWrite++;
00591             }
00592             pRead++;
00593         }
00594         *pWrite = 0;
00595     } else {
00596         //
00597         // 1. search all points in the name
00598         //
00599         pRead = pLongName;
00600         bPointCount = 0;
00601         while (*pRead != 0) {
00602             if (*pRead == '.') {
00603                 bPointCount++;
00604             }
00605             pRead++;
00606         }
00607 
00608         if (bPointCount >= 2) {
00609             //
00610             // Remove the points...
00611             //
00612             bPointCount--;
00613 
00614             pRead = pLongName;
00615             pWrite = pLongName;
00616 
00617             while (*pRead != 0) {
00618                 if ((*pRead == '.') && (bPointCount)) {
00619                     bPointCount--;
00620                 } else {
00621                     *pWrite = *pRead;
00622                     pWrite++;
00623                 }
00624                 pRead++;
00625             }
00626             *pWrite = 0;
00627         }
00628     }
00629 
00630     return (pLongName);
00631 }
00632 
00633 /************************************************************/
00634 /*  FindFileATAPI                                           */
00635 /*                                                          */
00636 /*  Find a file by a given name pLongName.                  */
00637 /*  For ATAPI, we have NO cluster. A cluster is the same    */
00638 /*  as a sector.                                            */
00639 /************************************************************/
00640 static DWORD FindFileATAPI(DRIVE_INFO * pDrive,
00641                            FAT32_DIRECTORY_ENTRY * pSearchEntry,
00642                            char *pLongName, DWORD dwDirCluster, DWORD * pFileSize, int nIsLongName)
00643 {
00644     DWORD dwSector;
00645     DWORD dwDirSector;
00646     DWORD dwMaxDirSector;
00647     WORD wByteCount;
00648     BYTE bLongNameLen;
00649     BYTE bSearchFlags;
00650     ATAPI2_DIRECTORY_RECORD *pDirEntry;
00651 
00652     dwSector = 0;
00653     dwDirSector = dwDirCluster;
00654 
00655     dwMaxDirSector = pDrive->dwFirstRootDirSector + pDrive->dwRootDirSectors - 1;
00656 
00657     bSearchFlags = 0;
00658     if (pSearchEntry->Attribute == DIRECTORY_ATTRIBUTE_DIRECTORY) {
00659         bSearchFlags = 0x02;
00660         pLongName = RemoveChar(pLongName, TRUE);
00661     } else {
00662         pLongName = RemoveChar(pLongName, FALSE);
00663     }
00664 
00665     //
00666     // ' ' and '-' are not allowed in the name, change it...
00667     //
00668     pLongName = CheckATAPIName(pLongName);
00669     bLongNameLen = strlen(pLongName);
00670 
00671     while (dwDirCluster <= dwMaxDirSector) {
00672         IDEReadSectors(pDrive->bDevice, pSectorBuffer, dwDirCluster, 1);
00673 
00674         wByteCount = 0;
00675         pDirEntry = (ATAPI2_DIRECTORY_RECORD *) & pSectorBuffer[0];
00676         while (wByteCount < pDrive->dwClusterSize) {
00677             if (pDirEntry->bRecordSize == 0) {
00678                 break;
00679             } else {
00680                 //
00681                 // Check pDirEntry
00682                 //
00683                 if (((pDirEntry->bFlags & 0x03) == bSearchFlags) &&
00684                     (pDirEntry->bIdentifierLength >= bLongNameLen) &&
00685                     (strncmp((char*)&pDirEntry->bName[0], pLongName, bLongNameLen) == 0)) {
00686                     //
00687                     // We have found the file :-)
00688                     // 
00689                     dwSector = pDirEntry->dwFirstSector;
00690                     *pFileSize = pDirEntry->dwEntrySize;
00691                     // Sorry for the return here :-(
00692                     return (dwSector);
00693                 }
00694 
00695                 wByteCount += pDirEntry->bRecordSize;
00696                 pDirEntry = (ATAPI2_DIRECTORY_RECORD *) & pSectorBuffer[wByteCount];
00697             }
00698         }
00699         dwDirCluster++;
00700     }
00701 
00702     return (dwSector);
00703 }
00704 #endif
00705 
00706 /************************************************************/
00707 /*  FindFile                                                */
00708 /*                                                          */
00709 /*  Find a file by a given name pLongName.                  */
00710 /*                                                          */
00711 /*  It is possible that a SHORT name like "enlogo.gif"      */
00712 /*  is stored as a LONG name. I have seen this              */
00713 /*  nasty behaviour by Win98. Therefore I will check        */
00714 /*  the long name too, even if nIsLongName is FALSE.        */
00715 /************************************************************/
00716 static DWORD FindFile(DRIVE_INFO * pDrive,
00717                       FAT32_DIRECTORY_ENTRY * pSearchEntry, char *pLongName, DWORD dwDirCluster, DWORD * pFileSize, int nIsLongName)
00718 {
00719     int i, x;
00720     BYTE bError;
00721     int nNameLen;
00722     int nMaxLen;
00723     BYTE bFound;
00724     BYTE bEndLoop;
00725     BYTE bOrder;
00726     BYTE bMaxOrder;
00727     int nDirMaxSector;
00728     DWORD dwSector;
00729     DWORD dwNewCluster;
00730     FAT32_DIRECTORY_ENTRY *pDirEntryShort;
00731     FAT32_DIRECTORY_ENTRY_LONG *pDirEntryLong;
00732     char *pDirName = 0;
00733     FAT_DIR_TABLE *pDirTable;
00734 
00735     bError = FALSE;
00736     *pFileSize = 0;
00737     dwNewCluster = 0;
00738 
00739     nNameLen = strlen(pLongName);
00740 
00741     bMaxOrder = (BYTE) ((nNameLen + 12) / 13);
00742     nMaxLen = (int) (bMaxOrder * 13);
00743     if (nMaxLen >= (FAT_LONG_NAME_LEN - 1)) {
00744         bError = TRUE;
00745     }
00746 
00747     bOrder = (BYTE) (0x40 | bMaxOrder);
00748     if (bOrder == 0xE5) {
00749         //
00750         // I do not know what should I do if the bOrder is 0xe5.
00751         // This is a sign for a "empty" entry. 
00752         //
00753         bError = TRUE;
00754     }
00755 
00756     if (bError == FALSE) {
00757         bFound = FALSE;
00758         bEndLoop = FALSE;
00759         while ((bEndLoop == FALSE) && (dwDirCluster != 0)) {
00760             dwSector = GetFirstSectorOfCluster(pDrive, dwDirCluster);
00761             nDirMaxSector = (int) pDrive->bSectorsPerCluster;
00762 
00763             //
00764             // Test for special case dwDirCluster and FAT16.
00765             //
00766             if ((dwDirCluster == 1) && (pDrive->bIsFAT32 == FALSE)) {
00767                 dwSector = pDrive->dwFirstRootDirSector;
00768                 nDirMaxSector = (int) pDrive->dwRootDirSectors;
00769             }
00770             //
00771             // One cluster has SecPerCluster sectors.
00772             //
00773             for (i = 0; i < nDirMaxSector; i++) {
00774                 IDEReadSectors(pDrive->bDevice, pSectorBuffer, dwSector + i, 1);
00775                 pDirTable = (FAT_DIR_TABLE *) pSectorBuffer;
00776 
00777                 //
00778                 // And one sector has 16 entries.
00779                 //
00780                 // IDE_SECTOR_SIZE / sizeof(FAT32_DIRECTORY_ENTRY) = 16
00781                 //
00782                 for (x = 0; x < 16; x++) {
00783                     if (bFound == TRUE) {
00784                         pDirEntryShort = (FAT32_DIRECTORY_ENTRY *) & pDirTable->aShort[x];
00785                         dwNewCluster = pDirEntryShort->HighCluster;
00786                         dwNewCluster = (dwNewCluster << 16) | (DWORD) pDirEntryShort->LowCluster;
00787                         *pFileSize = pDirEntryShort->FileSize;
00788                         bEndLoop = TRUE;
00789                         break;
00790                     }
00791                     //
00792                     // Check for valid entry.
00793                     //
00794                     pDirEntryShort = (FAT32_DIRECTORY_ENTRY *) & pDirTable->aShort[x];
00795                     pDirEntryLong = (FAT32_DIRECTORY_ENTRY_LONG *) & pDirTable->aLong[x];
00796 
00797                     if (nIsLongName == FALSE) {
00798                         //
00799                         // Check if it could be a short name. If Win2000 tell us it
00800                         // is a short name, it is true. But with Win98 we must
00801                         // test both, short and long...
00802                         //
00803                         if ((pDirEntryShort->Name[0] != 0xE5) && (pDirEntryShort->Name[0] != 0x00)) {
00804                             if (memcmp(pDirEntryShort, pSearchEntry, 11) == 0) {
00805                                 //
00806                                 // Check for the correct attribute, this is done with
00807                                 // the '&' and not with the memcmp.
00808                                 // With the '&' it is possible to find a hidden archive too :-)
00809                                 //
00810                                 if ((pDirEntryShort->Attribute & pSearchEntry->Attribute) == pSearchEntry->Attribute) {
00811 
00812                                     dwNewCluster = pDirEntryShort->HighCluster;
00813                                     dwNewCluster = (dwNewCluster << 16) | (DWORD) pDirEntryShort->LowCluster;
00814                                     *pFileSize = pDirEntryShort->FileSize;
00815 
00816                                     bEndLoop = TRUE;
00817                                     break;
00818 
00819                                 }       /* endif Attribute */
00820                             }   /* endif test Name+Ext */
00821                         }       /* endif Name[0] != 0xe5, 0x00 */
00822                     }
00823                     /* endif nIsLongName == FALSE */
00824                     if ((pDirEntryLong->Attribute == DIRECTORY_ATTRIBUTE_LONG_NAME) && (pDirEntryLong->Order == bOrder)) {
00825                         //
00826                         // Next bOrder is bOrder--
00827                         //  
00828                         if (bOrder & 0x40) {
00829                             bOrder &= ~0x40;
00830 
00831                             //
00832                             // Get the space for the name.
00833                             //
00834                             pDirName = pLongName2;
00835 
00836                             //
00837                             // Set the end of string.
00838                             //
00839                             pDirName[nMaxLen--] = 0;
00840                         }
00841 
00842                         pDirName[nMaxLen--] = GetLongChar(pDirEntryLong->Name3[1]);
00843                         pDirName[nMaxLen--] = GetLongChar(pDirEntryLong->Name3[0]);
00844 
00845                         pDirName[nMaxLen--] = GetLongChar(pDirEntryLong->Name2[5]);
00846                         pDirName[nMaxLen--] = GetLongChar(pDirEntryLong->Name2[4]);
00847                         pDirName[nMaxLen--] = GetLongChar(pDirEntryLong->Name2[3]);
00848                         pDirName[nMaxLen--] = GetLongChar(pDirEntryLong->Name2[2]);
00849                         pDirName[nMaxLen--] = GetLongChar(pDirEntryLong->Name2[1]);
00850                         pDirName[nMaxLen--] = GetLongChar(pDirEntryLong->Name2[0]);
00851 
00852                         pDirName[nMaxLen--] = GetLongChar(pDirEntryLong->Name1[4]);
00853                         pDirName[nMaxLen--] = GetLongChar(pDirEntryLong->Name1[3]);
00854                         pDirName[nMaxLen--] = GetLongChar(pDirEntryLong->Name1[2]);
00855                         pDirName[nMaxLen--] = GetLongChar(pDirEntryLong->Name1[1]);
00856                         pDirName[nMaxLen--] = GetLongChar(pDirEntryLong->Name1[0]);
00857 
00858                         bOrder--;
00859                         if (bOrder == 0) {
00860                             //
00861                             // Now compare the name.
00862                             //
00863                             bOrder = (BYTE) (0x40 | bMaxOrder);
00864                             nMaxLen = (int) (bMaxOrder * 13);
00865                             if (memcmp(pLongName, pDirName, strlen(pLongName)) == 0) {
00866                                 //
00867                                 // The next entry will be the correct entry.
00868                                 //
00869                                 bFound = TRUE;
00870                             }
00871                         }
00872                     }
00873                     /* pDirEntryLong->Order == bOrder */
00874                 }               /* endfor x<16 */
00875 
00876                 if (bEndLoop == TRUE) {
00877                     break;
00878                 }
00879             }
00880 
00881             if (bEndLoop == FALSE) {
00882                 //
00883                 // No file found in this cluster, get the next one.
00884                 //
00885                 dwDirCluster = GetNextCluster(pDrive, dwDirCluster);
00886             }
00887         }                       /* endwhile */
00888 
00889     }
00890     /* endif bError == FALSE */
00891     return (dwNewCluster);
00892 }
00893 
00894 #if (IDE_SUPPORT_ATAPI == 1)
00895 /************************************************************/
00896 /*  MountATAPI                                              */
00897 /************************************************************/
00898 static int MountATAPI(int nDrive)
00899 {
00900     int nError = IDE_OK;
00901     DWORD dwSector;
00902     DWORD dwPVDSector;
00903     DRIVE_INFO *pDrive;
00904     ATAPI_PVD *pPVD;
00905 
00906     pDrive = &sDriveInfo[nDrive];
00907     dwSector = ATAPI_START_SEARCH_SECTOR;
00908     dwPVDSector = 0;
00909     while (dwSector <= ATAPI_MAX_SEARCH_SECTOR) {
00910         nError = IDEReadSectors(nDrive, pSectorBuffer, dwSector, 1);
00911         if (nError != IDE_OK) {
00912             break;
00913         } else {
00914             if ((pSectorBuffer[0] == ATAPI_PVD_DESC) &&
00915                 (pSectorBuffer[1] == 'C') && (pSectorBuffer[2] == 'D') &&
00916                 (pSectorBuffer[3] == '0') && (pSectorBuffer[4] == '0') && (pSectorBuffer[5] == '1')) {
00917                 dwPVDSector = dwSector;
00918             }
00919             if ((pSectorBuffer[0] == ATAPI_VDST_DESC) &&
00920                 (pSectorBuffer[1] == 'C') && (pSectorBuffer[2] == 'D') &&
00921                 (pSectorBuffer[3] == '0') && (pSectorBuffer[4] == '0') && (pSectorBuffer[5] == '1')) {
00922                 break;
00923             }
00924         }
00925         dwSector++;
00926     }
00927 
00928     if (dwPVDSector != 0) {
00929         IDEReadSectors(nDrive, pSectorBuffer, dwPVDSector, 1);
00930         pPVD = (ATAPI_PVD *) pSectorBuffer;
00931 
00932         pDrive->bSectorsPerCluster = 1;
00933         pDrive->dwFirstRootDirSector = *(DWORD *) & pPVD->rootdir[2];
00934         pDrive->dwFAT1StartSector = pPVD->firstsek_LEpathtab1_LE;
00935         pDrive->dwFAT2StartSector = pPVD->firstsek_LEpathtab2_LE;
00936 
00937         pDrive->dwRootDirSectors = pDrive->dwFAT1StartSector - pDrive->dwFirstRootDirSector;
00938         pDrive->dwRootCluster = pDrive->dwFirstRootDirSector;
00939         pDrive->dwClusterSize = (DWORD) pDrive->wSectorSize;
00940 
00941         //nError = IDEATAPISetCDSpeed(nDrive, 0xFFFF);
00942     }
00943 
00944     return (nError);
00945 }
00946 #endif
00947 
00948 /************************************************************/
00949 /*  MountIDE                                                 */
00950 /************************************************************/
00951 static int MountIDE(int nDrive)
00952 {
00953     int nError;
00954     int i;
00955     DWORD dwSector;
00956     DWORD dwFATSz;
00957     DWORD dwRootDirSectors;
00958     FAT32_PARTITION_TABLE *pPartitionTable;
00959     FAT32_BOOT_RECORD *pBootRecord;
00960     DRIVE_INFO *pDrive;
00961 
00962     nError = IDE_OK;
00963     i = nDrive;
00964     pDrive = &sDriveInfo[nDrive];
00965     dwSector = 0;
00966 
00967     if (pDrive->bFlags & FLAG_FAT_IS_ZIP) {
00968         dwSector = ZIP_DRIVE_BR_SECTOR;
00969     } else {
00970         //
00971         // Try to find a PartitionTable.
00972         // 
00973         nError = IDEReadSectors(nDrive, pSectorBuffer, 0, 1);
00974         if (nError == IDE_OK) {
00975             pPartitionTable = (FAT32_PARTITION_TABLE *) pSectorBuffer;
00976 
00977             if (pPartitionTable->Signature == FAT_SIGNATURE) {
00978                 if (pPartitionTable->Partition[0].NumSectors) {
00979                     //
00980                     // We found a PartitionTable, read BootRecord.
00981                     // 
00982                     dwSector = pPartitionTable->Partition[0].StartSectors;
00983                 }
00984             }
00985         }
00986     }
00987 
00988     if (dwSector != 0) {
00989         IDEReadSectors(i, pSectorBuffer, dwSector, 1);
00990         pBootRecord = (FAT32_BOOT_RECORD *) pSectorBuffer;
00991 
00992         //
00993         // Test valid BootRecord.
00994         //
00995         if (pBootRecord->Signature == FAT_SIGNATURE) {
00996             pDrive->bSectorsPerCluster = pBootRecord->SecPerClus;
00997 
00998             if (pBootRecord->FATSz16 != 0) {
00999                 dwFATSz = pBootRecord->FATSz16;
01000                 pDrive->bIsFAT32 = FALSE;
01001                 pDrive->dwRootCluster = 1;      /* special value, see */
01002                 /* FindFile           */
01003             } else {
01004                 dwFATSz = pBootRecord->Off36.FAT32.FATSz32;
01005                 pDrive->bIsFAT32 = TRUE;
01006                 pDrive->dwRootCluster = pBootRecord->Off36.FAT32.RootClus;
01007             }
01008 
01009             dwRootDirSectors = ((pBootRecord->RootEntCnt * 32) + (pBootRecord->BytsPerSec - 1)) / pBootRecord->BytsPerSec;
01010 
01011             sDriveInfo[i].dwFAT1StartSector = pBootRecord->HiddSec + pBootRecord->RsvdSecCnt;
01012 
01013             pDrive->dwFAT2StartSector = pDrive->dwFAT1StartSector + dwFATSz;
01014 
01015             sDriveInfo[i].dwCluster2StartSector =
01016                 pBootRecord->HiddSec + pBootRecord->RsvdSecCnt + (pBootRecord->NumFATs * dwFATSz) + dwRootDirSectors;
01017 
01018             pDrive->dwClusterSize = pBootRecord->SecPerClus * pDrive->wSectorSize;
01019 
01020             pDrive->dwRootDirSectors = dwRootDirSectors;
01021             pDrive->dwFirstRootDirSector = pDrive->dwFAT2StartSector + dwFATSz;
01022 
01023         }                       /* endif pBootRecord->Signature */
01024     }
01025     /* endif dwSector != 0 */
01026     return (nError);
01027 }
01028 
01029 /*==========================================================*/
01030 /*  DEFINE: All code exported by the NUTDEVICE              */
01031 /*==========================================================*/
01032 /************************************************************/
01033 /*  FATMountDrive                                           */
01034 /************************************************************/
01035 static int FATMountDrive(int nDrive)
01036 {
01037     BYTE i;
01038     int nError;
01039 
01040     nError = IDE_OK;
01041 
01042     FATLock();
01043 
01044     nDrive = nDrive;
01045 
01046     if (pLongName1 == NULL) {
01047         pLongName1 = (char *) NutHeapAlloc(FAT_LONG_NAME_LEN);
01048     }
01049     if (pLongName2 == NULL) {
01050         pLongName2 = (char *) NutHeapAlloc(FAT_LONG_NAME_LEN);
01051     }
01052     if (pSectorBuffer == NULL) {
01053         pSectorBuffer = (BYTE *) NutHeapAlloc(MAX_SECTOR_SIZE);
01054     }
01055 
01056     if ((pSectorBuffer != NULL) && (pLongName1 != NULL) && (pLongName2 != NULL)) {
01057 
01058         for (i = 0; i < FAT_MAX_DRIVE; i++) {
01059             memset((BYTE *) & sDriveInfo[i], 0x00, sizeof(DRIVE_INFO));
01060 
01061             sDriveInfo[i].bDevice = i;
01062             sDriveInfo[i].wSectorSize = IDEGetSectorSize(i);
01063 
01064             if (IDEIsCDROMDevice(i) == TRUE) {
01065                 sDriveInfo[i].bFlags |= FLAG_FAT_IS_CDROM;
01066             }
01067 
01068             if (IDEIsZIPDevice(i) == TRUE) {
01069                 sDriveInfo[i].bFlags |= FLAG_FAT_IS_ZIP;
01070             }
01071 
01072             switch (sDriveInfo[i].wSectorSize) {
01073             case IDE_SECTOR_SIZE:{
01074                     nError = MountIDE(i);
01075                     break;
01076                 }
01077 #if (IDE_SUPPORT_ATAPI == 1)
01078             case ATAPI_SECTOR_SIZE:{
01079                     nError = MountATAPI(i);
01080                     break;
01081                 }
01082 #endif
01083             default:{
01084                     nError = IDE_ERROR;
01085                     break;
01086                 }
01087             }
01088 
01089         }                       /* endfor i<FAT32_MAX_DRIVE */
01090     }
01091     /* endif pSectorBuffer != NULL */
01092     FATFree();
01093 
01094     return (nError);
01095 }
01096 
01097 /************************************************************/
01098 /*  FATUnMountDrive                                         */
01099 /************************************************************/
01100 static int FATUnMountDrive(int nDrive)
01101 {
01102     int nError;
01103     DRIVE_INFO *pDrive;
01104 
01105     FATLock();
01106 
01107     nError = FAT_OK;
01108 
01109     if ((nDrive >= IDE_DRIVE_C) && (nDrive <= IDE_DRIVE_D)) {
01110         pDrive = &sDriveInfo[nDrive];
01111         pDrive->bSectorsPerCluster = 0;
01112     } else {
01113         nError = FAT_ERROR;
01114     }
01115 
01116     FATFree();
01117 
01118     return (nError);
01119 }
01120 
01121 /************************************************************/
01122 /*  CFMount                                                 */
01123 /************************************************************/
01124 static void CFMount(int nDrive)
01125 {
01126     BYTE *pSectorBuffer;
01127 
01128     pSectorBuffer = (BYTE *) NutHeapAlloc(MAX_SECTOR_SIZE);
01129     if (pSectorBuffer != NULL) {
01130         FATMountDrive(nDrive);
01131         NutHeapFree(pSectorBuffer);
01132     }
01133 }
01134 
01135 /************************************************************/
01136 /*  CFUnMount                                               */
01137 /************************************************************/
01138 static void CFUnMount(int nDrive)
01139 {
01140     FATUnMountDrive(nDrive);
01141 }
01142 
01143 /************************************************************/
01144 /*  FATInit                                                 */
01145 /************************************************************/
01146 static int FATInit(NUTDEVICE * pDevice)
01147 {
01148     int nError;
01149     int nIDEMode;
01150     BYTE *pSectorBuffer;
01151 
01152     nError = NUTDEV_OK;
01153     nIDEMode = IDE_HARDDISK;
01154     pSectorBuffer = NULL;
01155 
01156     if (gnIsInit == FALSE) {
01157         gnIsInit = TRUE;
01158         //
01159         // Get the mode.
01160         //
01161         switch (pDevice->dev_base) {
01162         case FAT_MODE_IDE_HD:
01163             nIDEMode = IDE_HARDDISK;
01164             break;
01165         case FAT_MODE_IDE_HD_7MHZ:
01166             nIDEMode = IDE_HARDDISK_7MHZ;
01167             break;
01168         case FAT_MODE_IDE_CF:
01169             nIDEMode = IDE_COMPACT_FLASH;
01170             break;
01171         case FAT_MODE_MEM_CF:
01172             nIDEMode = MEM_8BIT_COMPACT_FLASH;
01173             break;
01174         default:
01175             nError = NUTDEV_ERROR;
01176             break;
01177         }
01178 
01179         if (nError == NUTDEV_OK) {
01180 
01181             //
01182             // Init my semaphore.
01183             //
01184             FATSemaInit();
01185 
01186             pSectorBuffer = (BYTE *) NutHeapAlloc(MAX_SECTOR_SIZE);
01187             if (pSectorBuffer != NULL) {
01188                 IDEInit(0, nIDEMode, CFMount, CFUnMount);
01189 
01190                 IDEMountDevice(IDE_DRIVE_C, pSectorBuffer);
01191                 FATMountDrive(IDE_DRIVE_C);
01192 
01193                 NutHeapFree(pSectorBuffer);
01194             }                   /* endif pSectorBuffer != NULL */
01195         }                       /* endif nError == NUTDEV_OK */
01196     }
01197     /* endif gnIsInit == FALSE */
01198     return (nError);
01199 }
01200 
01201 /************************************************************/
01202 /*  FATFileOpen                                             */
01203 /*                                                          */
01204 /*  Opens an existing file for reading.                     */
01205 /*                                                          */
01206 /*  Parameters: pName points to a string that specifies the */
01207 /*              name of the file to open. The name must     */
01208 /*              exactly match the full pathname of the file.*/
01209 /*                                                          */
01210 /*  Returns:    A pointer to a FILE structure that can be   */
01211 /*              used to read the file and retrieve          */
01212 /*              information about the file.                 */
01213 /*                                                          */
01214 /*              A return value of -1 indicates an error.    */
01215 /************************************************************/
01216 static NUTFILE *FATFileOpen(NUTDEVICE * pDevice, CONST char *pName, int nMode, int nAccess)
01217 {
01218     int i, x;
01219     int nError;
01220     int nEndWhile;
01221     DWORD dwFileSize;
01222     DWORD dwCluster;
01223     FHANDLE *hFile;
01224     DRIVE_INFO *pDrive;
01225     FAT32_DIRECTORY_ENTRY sDirEntry;
01226 
01227     NUTFILE *hNUTFile;
01228 
01229     int nLongName;
01230     char *pLongName;
01231     char *pShortName;
01232     char *pExtension;
01233 
01234     //
01235     // If the user has forgotten to call NUTDeviceOpen,
01236     // we must call FATInit.
01237     //
01238     if (gnIsInit == FALSE) {
01239         FATInit(pDevice);
01240     }
01241 
01242     FATLock();
01243 
01244     pDrive = NULL;
01245     nError = TRUE;
01246     nLongName = FALSE;
01247     pLongName = (char *) pLongName1;
01248 
01249     //
01250     // hFile is our FAT-Handle.
01251     //
01252     hFile = NULL;
01253 
01254     //
01255     // hNUTFile is the.... correct, NUT handle.
01256     //   
01257     hNUTFile = (NUTFILE *) NUTDEV_ERROR;
01258 
01259     if (pDevice != NULL) {
01260         switch (pDevice->dev_name[4]) {
01261         case 'C':{
01262                 pDrive = &sDriveInfo[IDE_DRIVE_C];
01263                 break;
01264             }
01265         case 'D':{
01266                 pDrive = &sDriveInfo[IDE_DRIVE_D];
01267                 break;
01268             }
01269         }
01270     }
01271 
01272     if ((pDrive != NULL) && (pDrive->bSectorsPerCluster != 0) && (pName[0] != 0)) {
01273 
01274         //
01275         // Create a new file handle.
01276         //    
01277         hFile = (FHANDLE *) NutHeapAlloc(sizeof(FHANDLE));
01278 
01279         if ((pDrive->dwFAT1StartSector) && (hFile != NULL) && (*pName != '.')) {
01280 
01281             memset(hFile, 0x00, sizeof(FHANDLE));
01282 
01283             //
01284             // Start by the ROOT dir...
01285             //
01286             dwCluster = pDrive->dwRootCluster;
01287 
01288             //
01289             // If the first char a "/", jump over, e.g. "/index.html"
01290             // 
01291             //
01292             if (*pName == '/') {
01293                 pName++;
01294             }
01295 
01296             nEndWhile = FALSE;
01297             while (nEndWhile == FALSE) {        /* master loop */
01298 
01299                 nLongName = FALSE;
01300 
01301                 //
01302                 // Get Name
01303                 //
01304                 i = 0;
01305                 while ((*pName != '/') && (*pName != '\\') && (*pName != 0)) {
01306 
01307                     if (i >= (FAT_LONG_NAME_LEN - 1)) {
01308                         nEndWhile = TRUE;
01309                         break;
01310                     }
01311 
01312                     pLongName[i] = toupper(*pName);
01313 
01314                     i++;
01315                     pName++;
01316                 }               /* endwhile Name */
01317 
01318                 if (nEndWhile == FALSE) {
01319                     pLongName[i] = 0;
01320 
01321                     //
01322                     // Check if it is a Long Directory Entry.
01323                     // Yes, I know that 'i' is the length of the string.
01324                     // But the code is easier to read with the next strlen.
01325                     //
01326                     if (strlen(pLongName) <= FAT_SHORT_NAME_LEN) {
01327                         //
01328                         // It could be a ShortName, but "abc.defg" is possible
01329                         // and this is a long name too. Therfore we need some tests.
01330                         //
01331                         pExtension = strchr(pLongName, '.');
01332                         if (pExtension == NULL) {
01333                             if (strlen(pLongName) > FAT_NAME_LEN) {
01334                                 nLongName = TRUE;
01335                             } else {
01336                                 nLongName = FALSE;
01337                             }
01338                         } else {
01339                             //
01340                             // Check the length of the extensions.
01341                             //
01342                             pExtension++;       /* jump over the '.' */
01343                             if (strlen(pExtension) > 3) {
01344                                 nLongName = TRUE;
01345                             }
01346                         }
01347                     } else {    /* Len > FAT_SHORT_NAME_LEN */
01348                         //
01349                         // Now we have a LongName, sure.
01350                         // See the "nasty Win98" in FindFile :-)
01351                         //
01352                         nLongName = TRUE;
01353                     }
01354 
01355                     //
01356                     // Here we knows, if we have a LongName or ShortName.
01357                     //
01358                     if (nLongName == FALSE) {
01359                         //
01360                         // ShortName
01361                         //
01362                         pShortName = pLongName;
01363                         memset(&sDirEntry, 0x00, sizeof(FAT32_DIRECTORY_ENTRY));
01364                         memset(sDirEntry.Name, 0x20, FAT_NAME_LEN);
01365                         memset(sDirEntry.Extension, 0x20, FAT_EXT_LEN);
01366 
01367                         //
01368                         // Get the name
01369                         //
01370                         i = 0;
01371                         while ((pShortName[i] != '.') && (pShortName[i] != 0)) {
01372                             sDirEntry.Name[i] = pShortName[i];
01373                             i++;
01374                         }
01375                         //
01376                         // And the extension
01377                         //
01378                         if (pShortName[i] == '.') {
01379                             i++;        /* jump over the '.' */
01380                             x = 0;
01381                             while (pShortName[i] != 0) {
01382                                 sDirEntry.Extension[x] = pShortName[i];
01383                                 i++;
01384                                 x++;
01385                             }
01386                         }
01387                     }
01388                     //
01389                     // The file could be a long or short one.
01390                     // I have seen that Win98 store the short filename
01391                     // in a long one :-(
01392                     //
01393                     switch (*pName) {
01394                         //
01395                         // The file is an ARCHIVE
01396                         //
01397                     case 0:{
01398                             nEndWhile = TRUE;
01399                             sDirEntry.Attribute = DIRECTORY_ATTRIBUTE_ARCHIVE;
01400 
01401                             if (pDrive->bFlags & FLAG_FAT_IS_CDROM) {
01402                                 dwCluster = FindFileATAPI(pDrive, &sDirEntry, pLongName, dwCluster, &dwFileSize, nLongName);
01403                             } else {
01404 #if (IDE_SUPPORT_ATAPI == 1)
01405                                 dwCluster = FindFile(pDrive, &sDirEntry, pLongName, dwCluster, &dwFileSize, nLongName);
01406 #else
01407                                 dwCluster = 0;
01408 #endif
01409                             }
01410                             if (dwCluster != 0) {
01411                                 hFile->dwFileSize = dwFileSize;
01412                                 hFile->dwStartCluster = dwCluster;
01413                                 hFile->dwReadCluster = dwCluster;
01414                                 hFile->dwFilePointer = 0;
01415                                 hFile->dwClusterPointer = 0;
01416                                 hFile->pDrive = pDrive;
01417                                 hFile->nLastError = FAT_OK;
01418                                 hFile->nEOF = FALSE;
01419 
01420                                 nError = FALSE;
01421                             }
01422                             break;
01423                         }       /* endcase 0 */
01424 
01425                         //
01426                         // The file is a DIRECTORY
01427                         //
01428                     case '/':
01429                     case '\\':{
01430                             pName++;    /* jump over the char */
01431 
01432                             sDirEntry.Attribute = DIRECTORY_ATTRIBUTE_DIRECTORY;
01433 
01434                             if (pDrive->bFlags & FLAG_FAT_IS_CDROM) {
01435                                 dwCluster = FindFileATAPI(pDrive, &sDirEntry, pLongName, dwCluster, &dwFileSize, nLongName);
01436                             } else {
01437 #if (IDE_SUPPORT_ATAPI == 1)
01438                                 dwCluster = FindFile(pDrive, &sDirEntry, pLongName, dwCluster, &dwFileSize, nLongName);
01439 #else
01440                                 dwCluster = 0;
01441 #endif
01442                             }
01443                             if (dwCluster != 0) {
01444 
01445                                 //
01446                                 // The new Cluster is the Cluster of the directory
01447                                 //
01448 
01449                             } else {
01450                                 nEndWhile = TRUE;
01451                             }
01452                             break;
01453                         }       /* endcase / \ */
01454 
01455                     default:{
01456                             nEndWhile = TRUE;
01457                             break;
01458                         }
01459                     }           /* end switch */
01460 
01461                 }
01462                 /* endif nEndWhile == FALSE */
01463             }                   /* end while */
01464 
01465         }
01466         /* endif pDrive->dwFAT1StartSector */
01467         if (nError == TRUE) {
01468             //
01469             // We found no file, therefore we can delete our FAT-Handle
01470             //
01471             if (hFile != NULL) {
01472                 NutHeapFree(hFile);
01473             }
01474         } else {
01475             //
01476             // We have found a FILE and can create a NUT-Handle.
01477             //
01478             hNUTFile = NutHeapAlloc(sizeof(NUTFILE));
01479             if (hNUTFile != NULL) {
01480                 hNUTFile->nf_next = 0;
01481                 hNUTFile->nf_dev = pDevice;
01482                 hNUTFile->nf_fcb = hFile;
01483             } else {
01484                 //
01485                 // Error, no mem for the NUT-Handle, therefore we 
01486                 // can delete our FAT-Handle too.
01487                 //
01488                 NutHeapFree(hFile);
01489             }
01490         }
01491 
01492     }
01493     /* endif pName[0] != 0 */
01494     FATFree();
01495 
01496     return (hNUTFile);
01497 }
01498 
01499 /************************************************************/
01500 /*  FATFileClose                                            */
01501 /*                                                          */
01502 /*  Close a previously opened file.                         */
01503 /*                                                          */
01504 /*  Parameters: hNUTFile Identifies the file to close.      */
01505 /*              This pointer must have been created by      */
01506 /*              calling FAT32FileOpen().                    */
01507 /*                                                          */
01508 /*  Returns:    0 if the function is successfully closed,   */
01509 /*              -1 otherwise.                               */
01510 /************************************************************/
01511 static int FATFileClose(NUTFILE * hNUTFile)
01512 {
01513     int nError;
01514     FHANDLE *hFile;
01515 
01516     nError = NUTDEV_ERROR;
01517 
01518     FATLock();
01519 
01520     if (hNUTFile != NULL) {
01521         hFile = (FHANDLE *) hNUTFile->nf_fcb;
01522         if (hFile != NULL) {
01523             //
01524             // Clear our FAT-Handle
01525             //
01526             NutHeapFree(hFile);
01527         }
01528         //
01529         // Clear the NUT-Handle
01530         //
01531         NutHeapFree(hNUTFile);
01532 
01533         nError = NUTDEV_OK;
01534     }
01535 
01536     FATFree();
01537 
01538     return (nError);
01539 }
01540 
01541 /************************************************************/
01542 /*  FATFileSize                                             */
01543 /*                                                          */
01544 /*  Retrieve the size of a file.                            */
01545 /*                                                          */
01546 /*  Parameters: pFile Identifies the file to query.         */
01547 /*              This pointer must have been created by      */
01548 /*              calling FAT32FileOpen().                    */
01549 /*                                                          */
01550 /*  Returns:    The number of bytes in this file or         */
01551 /*              -1 if an error occured                      */
01552 /************************************************************/
01553 long FATFileSize(NUTFILE * hNUTFile)
01554 {
01555     long lSize;
01556     FHANDLE *hFile;
01557 
01558     FATLock();
01559 
01560     lSize = NUTDEV_ERROR;
01561 
01562     if (hNUTFile != NULL) {
01563         hFile = (FHANDLE *) hNUTFile->nf_fcb;
01564         if (hFile != NULL) {
01565             lSize = hFile->dwFileSize;
01566         }
01567     }
01568 
01569     FATFree();
01570 
01571     return (lSize);
01572 }
01573 
01574 #if 0
01575 /************************************************************/
01576 /*  FATFileSeek                                             */
01577 /*                                                          */
01578 /*  Move the file pointer to a new position.                */
01579 /*  It points to the next byte to be read from a file.      */
01580 /*  The file pointer is automatically incremented for       */
01581 /*  each byte read. When the file is opened, it is at       */
01582 /*  position 0, the beginning of the file.                  */
01583 /*                                                          */
01584 /*  Parameters: pFile Identifies the file to seek.          */
01585 /*              This pointer must have been created by      */
01586 /*              calling FAT32FileOpen().                    */
01587 /*                                                          */
01588 /*              lPos Specifies the new absolute position    */
01589 /*              of the file pointer.                        */
01590 /*                                                          */
01591 /*  Returns:    0 if the function is successful,            */
01592 /*              -1 otherwise.                               */
01593 /************************************************************/
01594 int FATFileSeek(FILE * pFile, long lPos)
01595 {
01596     int nError = NUTDEV_ERROR;
01597     FHANDLE *hFile;
01598 
01599     FATLock();
01600 
01601     hFile = (FHANDLE *) pFile;
01602 
01603     //
01604     // We must do some work here...
01605     //
01606     nError = FAT32_ERROR;
01607 
01608     FATFree();
01609 
01610     return (nError);
01611 }
01612 #endif
01613 
01614 /************************************************************/
01615 /*  FATFileRead                                             */
01616 /*                                                          */
01617 /*  Read data from a file.                                  */
01618 /*                                                          */
01619 /*  Parameters: pFile Identifies the file to read from.     */
01620 /*              This pointer must have been created by      */
01621 /*              calling FAT32FileOpen().                    */
01622 /*                                                          */
01623 /*              pData Points to the buffer that receives    */
01624 /*              the data.                                   */
01625 /*                                                          */
01626 /*              nSize Specifies the number of bytes to      */
01627 /*              read from the file.                         */
01628 /*                                                          */
01629 /*  Returns:    The number of bytes read from the file or   */
01630 /*               -1 if an error occured.                    */
01631 /************************************************************/
01632 int FATFileRead(NUTFILE * hNUTFile, void *pData, int nSize)
01633 {
01634     int nError;
01635     int nBytesRead;
01636     int nBytesToRead;
01637     FHANDLE *hFile;
01638     DRIVE_INFO *pDrive;
01639     BYTE *pByte;
01640     DWORD dwReadSector;
01641     DWORD dwSector;
01642     int nSectorCount;
01643     int nSectorOffset;
01644     WORD wSectorSize;
01645 
01646     nBytesRead = 0;
01647 
01648     FATLock();
01649 
01650     hFile = NULL;
01651     nError = NUTDEV_ERROR;
01652 
01653     if (hNUTFile != NULL) {
01654         hFile = (FHANDLE *) hNUTFile->nf_fcb;
01655     }
01656 
01657     if ((hFile != NULL) && (nSize != 0)) {
01658         if (hFile->dwFilePointer < hFile->dwFileSize) {
01659 
01660             if ((hFile->dwFilePointer + nSize) > hFile->dwFileSize) {
01661                 nSize = (int) (hFile->dwFileSize - hFile->dwFilePointer);
01662             }
01663 
01664             pDrive = (DRIVE_INFO *) hFile->pDrive;
01665             pByte = (BYTE *) pData;
01666 
01667             nBytesRead = nSize;
01668             wSectorSize = pDrive->wSectorSize;
01669 
01670             while (nSize) {
01671                 dwSector = GetFirstSectorOfCluster(pDrive, hFile->dwReadCluster);
01672                 nSectorCount = hFile->dwClusterPointer / wSectorSize;
01673                 nSectorOffset = hFile->dwClusterPointer % wSectorSize;
01674 
01675                 //
01676                 // (Sector + SectorCount) is the sector to read
01677                 // SectorOffset is the start position in the sector itself
01678                 //
01679                 dwReadSector = dwSector + nSectorCount;
01680 
01681                 nError = IDEReadSectors(pDrive->bDevice, pSectorBuffer, dwReadSector, 1);
01682                 if (nError == IDE_OK) {
01683                     //
01684                     // Find the size we can read from ONE sector
01685                     //
01686                     if (nSize > (int) wSectorSize) {
01687                         nBytesToRead = wSectorSize;
01688                     } else {
01689                         nBytesToRead = nSize;
01690                     }
01691 
01692                     //
01693                     // Test inside a sector
01694                     //
01695                     if ((nSectorOffset + nBytesToRead) > (int) wSectorSize) {
01696                         nBytesToRead = wSectorSize - nSectorOffset;
01697                     }
01698 
01699                     memcpy(pByte, &pSectorBuffer[nSectorOffset], nBytesToRead);
01700                     pByte += nBytesToRead;
01701 
01702                     hFile->dwFilePointer += nBytesToRead;
01703                     hFile->dwClusterPointer += nBytesToRead;
01704 
01705                     //
01706                     // Check for EOF
01707                     if (hFile->dwFilePointer >= hFile->dwFileSize) {
01708                         hFile->nEOF = TRUE;
01709                     }
01710 
01711                     if (hFile->dwClusterPointer >= pDrive->dwClusterSize) {
01712                         //
01713                         // We must switch to the next cluster
01714                         //
01715                         hFile->dwReadCluster = GetNextCluster(pDrive, hFile->dwReadCluster);
01716                         hFile->dwClusterPointer = 0;
01717                     }
01718 
01719                     nSize -= nBytesToRead;
01720 
01721                 } else {        /* IDEReadSectors Error */
01722 
01723                     nBytesRead = 0;
01724                     hFile->nLastError = FAT_ERROR_IDE;
01725                     break;
01726                 }               /* endif nError == IDE_OK */
01727 
01728             }                   /* endwhile */
01729 
01730         } else {                /* reached the EOF */
01731             hFile->nLastError = FAT_ERROR_EOF;
01732         }                       /* endif hFile->dwFilePointer < hFile->dwFileSize */
01733 
01734     }
01735     /* endif (hFile != NULL) && (nSize != 0) */
01736     FATFree();
01737 
01738     return (nBytesRead);
01739 }
01740 
01741 static int FATFileWrite(NUTFILE * hNUTFile, CONST void *pData, int nSize)
01742 {
01743     int nError;
01744 
01745     nError = NUTDEV_ERROR;
01746 
01747     return (nError);
01748 }
01749 
01750 #ifdef __HARVARD_ARCH__
01751 static int FATFileWriteP(NUTFILE * hNUTFile, PGM_P pData, int nSize)
01752 {
01753     int nError;
01754 
01755     nError = NUTDEV_ERROR;
01756 
01757     return (nError);
01758 }
01759 #endif
01760 
01761 
01762 //
01763 // FATC Device information structure.
01764 //
01765 NUTDEVICE devFATC = {
01766     0,                          /* Pointer to next device. */
01767     /* Unique device name.     */
01768     {'F', 'A', 'T', '_', 'C', 0, 0, 0, 0}
01769     ,
01770 
01771     IFTYP_STREAM,               /* Type of device.                   */
01772     2,                          /* Base address.                     */
01773     0,                          /* First interrupt number.           */
01774     0,                          /* Interface control block.          */
01775     0,                          /* Driver control block.             */
01776     FATInit,                    /* Driver initialization routine.    */
01777     0,                          /* Driver specific control function. */
01778     FATFileRead,                /* Driver specific read function.    */
01779     FATFileWrite,               /* Driver specific write function.   */
01780 #ifdef __HARVARD_ARCH__
01781     FATFileWriteP,              /* Driver specific write_p function. */
01782 #endif
01783     FATFileOpen,                /* Driver specific open function.    */
01784     FATFileClose,               /* Driver specific close function.   */
01785     FATFileSize
01786 };