• Main Page
  • Related Pages
  • Data Structures
  • Files
  • File List
  • Globals

dosfs.c

Go to the documentation of this file.
00001 /*
00002     DOSFS Embedded FAT-Compatible Filesystem
00003     (C) 2005 Lewin A.R.W. Edwards (sysadm@zws.com)
00004 
00005     You are permitted to modify and/or use this code in your own projects without
00006     payment of royalty, regardless of the license(s) you choose for those projects.
00007 
00008     You cannot re-copyright or restrict use of the code as released by Lewin Edwards.
00009 
00010     Notes
00011     =====
00012     Some platforms may require explicit pragmas or attributes to the structures
00013     and unions. For example, arm-gcc will require __attribute__ ((__packed__))
00014     otherwise it will try to be "smart" and place the uint8_t members on 4-byte
00015     boundaries. There is no truly elegant compiler-independent method to get
00016     around this sort of problem.
00017 
00018     The code assumes either a von Neumann architecture, or a compiler that
00019     is smart enough to understand where your pointers are aimed and emit
00020     the right kind of memory read and write instructions. The implications
00021     of this statement depend on your target processor and the compiler you
00022     are using. Be very careful not to straddle bank boundaries on bank-
00023     switched memory systems.
00024 
00025     Physical 32-bit sector numbers are used throughout. Therefore, the
00026     CHS geometry (if any) of the storage media is not known to DOSFS. Your
00027     sector r/w functions may need to query the CHS geometry and perform
00028     mapping.
00029 
00030     File timestamps set by DOSFS are always 1:01:00am on Jan 1, 2006. If
00031     your system has a concept of real time, you can enhance this.
00032 
00033     FILEINFO structures contain a pointer to the corresponding VOLINFO
00034     used to open the file, mainly in order to avoid mixups but also to
00035     obviate the need for an extra parameter to every file read/write. DOSFS
00036     assumes that the VOLINFO won't move around. If you need to move or
00037     destroy VOLINFOs pertaining to open files, you'll have to fix up the
00038     pointer in the FILEINFO structure yourself.
00039 
00040     The subdirectory delimiter is a forward slash ( '/' ) by default. The
00041     reason for this is to avoid the common programming error of forgetting
00042     that backslash is an escape character in C strings; i.e. "\MYDIR\FILE"
00043     is NOT what you want; "\\MYDIR\\FILE" is what you wanted to type. If you
00044     are porting DOS code into an embedded environment, feel free to change
00045     this #define.
00046 
00047     DOSFS does not have a concept of "current directory". A current directory
00048     is owned by a process, and a process is an operating system concept.
00049     DOSFS is a filesystem library, not an operating system. Therefore, any
00050     path you provide to a DOSFS call is assumed to be relative to the root of
00051     the volume.
00052 
00053     There is no call to close a file or directory that is open for reading or
00054     writing. You can simply destroy or reuse the data structures allocated for
00055     that operation; there is no internal state in DOSFS so no cleanup is
00056     necessary. Similarly, there is no call to close a file that is open for
00057     writing. (Observe that dosfs.c has no global variables. All state information
00058     is stored in data structures provided by the caller).
00059 
00060 */
00061 
00062 
00063 #include "circle_platform.h"
00064 
00065 #if SDCARD_SDIO
00066 #include "sdio_sd.h"               // SDIO interface
00067 #else
00068 #include "spi_sd.h"                // SPI interface
00069 #endif
00070 
00071 #include "dosfs.h"
00072 
00073 /* Private variables ---------------------------------------------------------*/
00074 //#if SDCARD_SDIO
00075 __IO SD_CardInfo SDCardInfo;
00076 __IO SD_Error Status = SD_OK;
00077 //#endif
00078 //ErrorStatus HSEStartUpStatus;
00079 
00080 
00081 /* Private typedef ---------------------------------------------------------*/
00082 typedef struct
00083 {
00084     long int quot;              /* Quotient. */
00085     long int rem;               /* Remainder */
00086 } ldiv_t;
00087 
00088 
00089 
00090 NODEBUG ldiv_t DFS_ldiv( s32 numer, s32 denom )
00091 {
00092     static ldiv_t ld;
00093 
00094     ld.quot = numer / denom;
00095     ld.rem = numer % denom;
00096 
00097     return ld;
00098 }
00099 
00100 #define DFS_div(x,y) DFS_ldiv(x,y)
00101 
00102 
00103 NODEBUG void* DFS_memset( void* dest, u8 c, s32 count )
00104 {
00105     u32 i;
00106 
00107     u8* val = ( u8* ) dest;
00108 
00109     for ( i = 0; i < count; i++ )
00110     {
00111         *val = c;
00112         val++;
00113     }
00114 
00115     return dest;
00116 }
00117 
00118 
00119 NODEBUG void* DFS_memcpy( void* dest, void* src, s32 count )
00120 {
00121 
00122     u8* d = ( u8* )dest;
00123     u8* s = ( u8* )src;
00124 
00125     while ( count-- > 0 )
00126         *d++ = *s++;
00127     return dest;
00128 }
00129 
00130 
00131 NODEBUG s32 DFS_memcmp( const void* s1, const void* s2, u32 n )
00132 {
00133     u8 u1, u2;
00134     u8* c1 = ( u8* ) s1;
00135     u8* c2 = ( u8* ) s2;
00136 
00137     for ( ; n-- ; c1++, c2++ )
00138     {
00139         u1 = * ( u8* ) c1;
00140         u2 = * ( u8* ) c2;
00141         if ( u1 != u2 )
00142         {
00143             return ( u1 - u2 );
00144         }
00145     }
00146     return 0;
00147 }
00148 
00149 /*NODEBUG s32 DFS_strlen (const u8 *str)
00150 {
00151     s32 n=0;
00152     const u8 *s = str;
00153 
00154     while (*s)
00155     {
00156         s++;
00157         n++;
00158     }
00159     return(n);
00160 }
00161 */ /* YRT20080204 => replaced by my_strlen*/
00162 
00163 NODEBUG void DFS_strcpy( u8* Dest ,  u8* Src )
00164 {
00165     /*  u8 * d= Dest;*/
00166 
00167     while ( *Src )
00168     {
00169         /*__YRT    *d++ = (*Src)++;  */
00170         *Dest++ = *Src++;
00171     }
00172 }
00173 
00174 
00175 
00176 NODEBUG u8* DFS_strncpy( u8* s1, const u8* s2, s32 n )
00177 {
00178     u8 c;
00179     u8* s = s1;
00180 
00181     --s1;
00182 
00183     if ( n >= 4 )
00184     {
00185         s32 n4 = n >> 2;
00186 
00187         for ( ;; )
00188         {
00189             c = *s2++;
00190             *++s1 = c;
00191             if ( c == '\0' )
00192                 break;
00193             c = *s2++;
00194             *++s1 = c;
00195             if ( c == '\0' )
00196                 break;
00197             c = *s2++;
00198             *++s1 = c;
00199             if ( c == '\0' )
00200                 break;
00201             c = *s2++;
00202             *++s1 = c;
00203             if ( c == '\0' )
00204                 break;
00205             if ( --n4 == 0 )
00206                 goto last_chars;
00207         }
00208         n = n - ( s1 - s ) - 1;
00209         if ( n == 0 )
00210             return s;
00211         goto zero_fill;
00212     }
00213 
00214 last_chars:
00215     n &= 3;
00216     if ( n == 0 )
00217         return s;
00218 
00219     do
00220     {
00221         c = *s2++;
00222         *++s1 = c;
00223         if ( --n == 0 )
00224             return s;
00225     }
00226     while ( c != '\0' );
00227 
00228 zero_fill:
00229     do
00230         *++s1 = '\0';
00231     while ( --n > 0 );
00232 
00233     return s;
00234 }
00235 
00236 NODEBUG s32 DFS_strcmp( u8* s1,  u8* s2 )
00237 {
00238     while ( *s1 == *s2 && *s1 != '\0' )
00239     {
00240         s1++;
00241         s2++;
00242     }
00243 
00244     /* Here we assume that characters are unsigned (0-255) */
00245 
00246     return *s1 - *s2;
00247 }
00248 
00249 
00250 /*===================================================================*/
00251 /* User-supplied functions*/
00252 
00253 //__IO SD_Error Status = SD_OK;
00254 
00255 NODEBUG uint32_t DFS_ReadSector( uint8_t unit, uint8_t* buffer, uint32_t sector, uint32_t count )
00256 {
00257 //YRT20110309
00258 //    u32* buffer32;
00259 //    buffer32 = ( u32* )buffer;
00260 
00261 //#if !SDCARD_SDIO
00262 //    SD_ReadBlock( buffer, sector << 9, SECTOR_SIZE );
00263 //    return 0;
00264 //#else
00265 //    __IO SD_Error Status = SD_OK;
00266 
00267     // Read the block
00268     if (SD_ReadBlock( buffer, sector << 9, SECTOR_SIZE ) != SD_OK)
00269         return 1;
00270     
00271 #if SDCARD_SDIO
00272     // Check the end of DMA transfer
00273     if ( SD_WaitReadOperation() == SD_OK )
00274     {
00275         // Check the end of SD operation
00276         do
00277         {
00278             Status = SD_GetStatus();
00279         }
00280         while ( Status == SD_TRANSFER_BUSY );
00281 
00282         if ( Status == SD_TRANSFER_OK )
00283             return 0;
00284         else
00285             return 1;
00286     }
00287     else
00288         return 1;
00289 #endif
00290 
00291 //#endif
00292 
00293 }
00294 
00295 
00296 NODEBUG uint32_t DFS_WriteSector( uint8_t unit, uint8_t* buffer, uint32_t sector, uint32_t count )
00297 {
00298 //YRT20110309
00299 //    u32* buffer32;
00300 //    buffer32 = ( u32* )buffer;
00301 
00302     /* Write block of 512 bytes on address 0 */
00303 //#if !SDCARD_SDIO
00304 //    SD_WriteBlock( buffer, sector << 9, SECTOR_SIZE );
00305 //    return 0;
00306 //#else
00307 //    __IO SD_Error Status = SD_OK;
00308 
00309     // Write the block
00310     if (SD_WriteBlock( buffer, sector << 9, SECTOR_SIZE ) != SD_OK)
00311         return 1;
00312 
00313 #if SDCARD_SDIO
00314     // Check the end of DMA transfer
00315     if ( SD_WaitWriteOperation() == SD_OK )
00316     {
00317         // Check the end of SD operation
00318         do
00319         {
00320             Status = SD_GetStatus();
00321         }
00322         while ( Status == SD_TRANSFER_BUSY );
00323 
00324         if ( Status == SD_TRANSFER_OK )
00325             return 0;
00326         else
00327             return 1;
00328     }
00329     else
00330         return 1;
00331 #endif    
00332 
00333 //#endif
00334 
00335 }
00336 
00337 
00338 /*===================================================================*/
00339 
00340 
00341 
00342 
00343 /*
00344     Get starting sector# of specified partition on drive #unit
00345     NOTE: This code ASSUMES an MBR on the disk.
00346     scratchsector should point to a SECTOR_SIZE scratch area
00347     Returns 0xffffffff for any error.
00348     If pactive is non-NULL, this function also returns the partition active flag.
00349     If pptype is non-NULL, this function also returns the partition type.
00350     If psize is non-NULL, this function also returns the partition size.
00351 */
00352 NODEBUG uint32_t DFS_GetPtnStart( uint8_t unit, uint8_t* scratchsector, uint8_t pnum, uint8_t* pactive, uint8_t* pptype, uint32_t* psize )
00353 {
00354     uint32_t result;
00355     PMBR mbr = ( PMBR ) scratchsector;
00356 
00357     // DOS ptable supports maximum 4 partitions
00358     if ( pnum > 3 )
00359         return DFS_ERRMISC;
00360 
00361     // Read MBR from target media
00362     if ( DFS_ReadSector( unit, scratchsector, 0, 1 ) )
00363     {
00364         return DFS_ERRMISC;
00365     }
00366 
00367     result = ( uint32_t ) mbr->ptable[pnum].start_0 |
00368              ( ( ( uint32_t ) mbr->ptable[pnum].start_1 ) << 8 ) |
00369              ( ( ( uint32_t ) mbr->ptable[pnum].start_2 ) << 16 ) |
00370              ( ( ( uint32_t ) mbr->ptable[pnum].start_3 ) << 24 );
00371 
00372     if ( pactive )
00373         *pactive = mbr->ptable[pnum].active;
00374 
00375     if ( pptype )
00376         *pptype = mbr->ptable[pnum].type;
00377 
00378     if ( psize )
00379         *psize = ( uint32_t ) mbr->ptable[pnum].size_0 |
00380                  ( ( ( uint32_t ) mbr->ptable[pnum].size_1 ) << 8 ) |
00381                  ( ( ( uint32_t ) mbr->ptable[pnum].size_2 ) << 16 ) |
00382                  ( ( ( uint32_t ) mbr->ptable[pnum].size_3 ) << 24 );
00383 
00384     return result;
00385 }
00386 
00387 
00388 /*
00389     Retrieve volume info from BPB and store it in a VOLINFO structure
00390     You must provide the unit and starting sector of the filesystem, and
00391     a pointer to a sector buffer for scratch
00392     Attempts to read BPB and glean information about the FS from that.
00393     Returns 0 OK, nonzero for any error.
00394 */
00395 NODEBUG uint32_t DFS_GetVolInfo( uint8_t unit, uint8_t* scratchsector, uint32_t startsector, PVOLINFO volinfo )
00396 {
00397     PLBR lbr = ( PLBR ) scratchsector;
00398     volinfo->unit = unit;
00399     volinfo->startsector = startsector;
00400 
00401     if ( DFS_ReadSector( unit, scratchsector, startsector, 1 ) )
00402         return DFS_ERRMISC;
00403 
00404     /* tag: OEMID, refer dosfs.h*/
00405     /*  strncpy(volinfo->oemid, lbr->oemid, 8);*/
00406     /*  volinfo->oemid[8] = 0;*/
00407 
00408     volinfo->secperclus = lbr->bpb.secperclus;
00409     volinfo->reservedsecs = ( uint16_t ) lbr->bpb.reserved_l |
00410                             ( ( ( uint16_t ) lbr->bpb.reserved_h ) << 8 );
00411 
00412     volinfo->numsecs = ( uint16_t ) lbr->bpb.sectors_s_l |
00413                        ( ( ( uint16_t ) lbr->bpb.sectors_s_h ) << 8 );
00414 
00415     if ( !volinfo->numsecs )
00416         volinfo->numsecs = ( uint32_t ) lbr->bpb.sectors_l_0 |
00417                            ( ( ( uint32_t ) lbr->bpb.sectors_l_1 ) << 8 ) |
00418                            ( ( ( uint32_t ) lbr->bpb.sectors_l_2 ) << 16 ) |
00419                            ( ( ( uint32_t ) lbr->bpb.sectors_l_3 ) << 24 );
00420 
00421     /* If secperfat is 0, we must be in a FAT32 volume; get secperfat*/
00422     /* from the FAT32 EBPB. The volume label and system ID string are also*/
00423     /* in different locations for FAT12/16 vs FAT32.*/
00424     volinfo->secperfat = ( uint16_t ) lbr->bpb.secperfat_l |
00425                          ( ( ( uint16_t ) lbr->bpb.secperfat_h ) << 8 );
00426     if ( !volinfo->secperfat )
00427     {
00428         volinfo->secperfat = ( uint32_t ) lbr->ebpb.ebpb32.fatsize_0 |
00429                              ( ( ( uint32_t ) lbr->ebpb.ebpb32.fatsize_1 ) << 8 ) |
00430                              ( ( ( uint32_t ) lbr->ebpb.ebpb32.fatsize_2 ) << 16 ) |
00431                              ( ( ( uint32_t ) lbr->ebpb.ebpb32.fatsize_3 ) << 24 );
00432 
00433         DFS_memcpy( volinfo->label, lbr->ebpb.ebpb32.label, 11 );
00434         volinfo->label[11] = 0;
00435 
00436         /* tag: OEMID, refer dosfs.h*/
00437         /*      DFS_memcpy(volinfo->system, lbr->ebpb.ebpb32.system, 8);*/
00438         /*      volinfo->system[8] = 0; */
00439     }
00440     else
00441     {
00442         DFS_memcpy( volinfo->label, lbr->ebpb.ebpb.label, 11 );
00443         volinfo->label[11] = 0;
00444 
00445         /* tag: OEMID, refer dosfs.h*/
00446         /*      DFS_memcpy(volinfo->system, lbr->ebpb.ebpb.system, 8);*/
00447         /*      volinfo->system[8] = 0; */
00448     }
00449 
00450     /* note: if rootentries is 0, we must be in a FAT32 volume.*/
00451     volinfo->rootentries = ( uint16_t ) lbr->bpb.rootentries_l |
00452                            ( ( ( uint16_t ) lbr->bpb.rootentries_h ) << 8 );
00453 
00454     /* after extracting raw info we perform some useful precalculations*/
00455     volinfo->fat1 = startsector + volinfo->reservedsecs;
00456 
00457     /* The calculation below is designed to round up the root directory size for FAT12/16*/
00458     /* and to simply ignore the root directory for FAT32, since it's a normal, expandable*/
00459     /* file in that situation.*/
00460     if ( volinfo->rootentries )
00461     {
00462         volinfo->rootdir = volinfo->fat1 + ( volinfo->secperfat * 2 );
00463         volinfo->dataarea = volinfo->rootdir + ( ( ( volinfo->rootentries * 32 ) + ( SECTOR_SIZE - 1 ) ) / SECTOR_SIZE );
00464     }
00465     else
00466     {
00467         volinfo->dataarea = volinfo->fat1 + ( volinfo->secperfat * 2 );
00468         volinfo->rootdir = ( uint32_t ) lbr->ebpb.ebpb32.root_0 |
00469                            ( ( ( uint32_t ) lbr->ebpb.ebpb32.root_1 ) << 8 ) |
00470                            ( ( ( uint32_t ) lbr->ebpb.ebpb32.root_2 ) << 16 ) |
00471                            ( ( ( uint32_t ) lbr->ebpb.ebpb32.root_3 ) << 24 );
00472     }
00473 
00474     /* Calculate number of clusters in data area and infer FAT type from this information.*/
00475     volinfo->numclusters = ( volinfo->numsecs - volinfo->dataarea ) / volinfo->secperclus;
00476     if ( volinfo->numclusters < 4085 )
00477         volinfo->filesystem = FAT12;
00478     else if ( volinfo->numclusters < 65525 )
00479         volinfo->filesystem = FAT16;
00480     else
00481         volinfo->filesystem = FAT32;
00482 
00483     return DFS_OK;
00484 }
00485 
00486 /*
00487     Fetch FAT entry for specified cluster number
00488     You must provide a scratch buffer for one sector (SECTOR_SIZE) and a populated VOLINFO
00489     Returns a FAT32 BAD_CLUSTER value for any error, otherwise the contents of the desired
00490     FAT entry.
00491     scratchcache should point to a UINT32. This variable caches the physical sector number
00492     last read into the scratch buffer for performance enhancement reasons.
00493 */
00494 NODEBUG uint32_t DFS_GetFAT( PVOLINFO volinfo, uint8_t* scratch, uint32_t* scratchcache, uint32_t cluster )
00495 {
00496     uint32_t offset, sector, result;
00497 
00498     if ( volinfo->filesystem == FAT12 )
00499     {
00500         offset = cluster + ( cluster >> 2 );
00501     }
00502     else if ( volinfo->filesystem == FAT16 )
00503     {
00504         offset = cluster * 2;
00505     }
00506     else if ( volinfo->filesystem == FAT32 )
00507     {
00508         offset = cluster * 4;
00509     }
00510     else
00511         return 0x0ffffff7;  // FAT32 bad cluster
00512 
00513     /* at this point, offset is the BYTE offset of the desired sector from the start*/
00514     /* of the FAT. Calculate the physical sector containing this FAT entry.*/
00515     sector = DFS_ldiv( offset, SECTOR_SIZE ).quot + volinfo->fat1;
00516 
00517     /* If this is not the same sector we last read, then read it into RAM*/
00518     if ( sector != *scratchcache )
00519     {
00520         if ( DFS_ReadSector( volinfo->unit, scratch, sector, 1 ) )
00521         {
00522             /* avoid anyone assuming that this cache value is still valid, which*/
00523             /* might cause disk corruption*/
00524             *scratchcache = 0;
00525             return 0x0ffffff7;  /* FAT32 bad cluster    */
00526         }
00527         *scratchcache = sector;
00528     }
00529 
00530     /* At this point, we "merely" need to extract the relevant entry.*/
00531     /* This is easy for FAT16 and FAT32, but a royal PITA for FAT12 as a single entry*/
00532     /* may span a sector boundary. The normal way around this is always to read two*/
00533     /* FAT sectors, but that luxury is (by design intent) unavailable to DOSFS.*/
00534     offset = DFS_ldiv( offset, SECTOR_SIZE ).rem;
00535 
00536     if ( volinfo->filesystem == FAT12 )
00537     {
00538         /* Special case for sector boundary - Store last byte of current sector.*/
00539         /* Then read in the next sector and put the first byte of that sector into*/
00540         /* the high byte of result.*/
00541         if ( offset == SECTOR_SIZE - 1 )
00542         {
00543             result = ( uint32_t ) scratch[offset];
00544             sector++;
00545             if ( DFS_ReadSector( volinfo->unit, scratch, sector, 1 ) )
00546             {
00547                 /* avoid anyone assuming that this cache value is still valid, which*/
00548                 /* might cause disk corruption*/
00549                 *scratchcache = 0;
00550                 return 0x0ffffff7;  /* FAT32 bad cluster    */
00551             }
00552             *scratchcache = sector;
00553             /* Thanks to Claudio Leonel for pointing out this missing line.*/
00554             result |= ( ( uint32_t ) scratch[0] ) << 8;
00555         }
00556         else
00557         {
00558             result = ( uint32_t ) scratch[offset] |
00559                      ( ( uint32_t ) scratch[offset + 1] ) << 8;
00560         }
00561         if ( cluster & 1 )
00562             result = result >> 4;
00563         else
00564             result = result & 0xfff;
00565     }
00566     else if ( volinfo->filesystem == FAT16 )
00567     {
00568         result = ( uint32_t ) scratch[offset] |
00569                  ( ( uint32_t ) scratch[offset + 1] ) << 8;
00570     }
00571     else if ( volinfo->filesystem == FAT32 )
00572     {
00573         result = ( ( uint32_t ) scratch[offset] |
00574                    ( ( uint32_t ) scratch[offset + 1] ) << 8 |
00575                    ( ( uint32_t ) scratch[offset + 2] ) << 16 |
00576                    ( ( uint32_t ) scratch[offset + 3] ) << 24 ) & 0x0fffffff;
00577     }
00578     else
00579         result = 0x0ffffff7;    // FAT32 bad cluster
00580     return result;
00581 }
00582 
00583 
00584 /*
00585     Set FAT entry for specified cluster number
00586     You must provide a scratch buffer for one sector (SECTOR_SIZE) and a populated VOLINFO
00587     Returns DFS_ERRMISC for any error, otherwise DFS_OK
00588     scratchcache should point to a UINT32. This variable caches the physical sector number
00589     last read into the scratch buffer for performance enhancement reasons.
00590 
00591     NOTE: This code is HIGHLY WRITE-INEFFICIENT, particularly for flash media. Considerable
00592     performance gains can be realized by caching the sector. However this is difficult to
00593     achieve on FAT12 without requiring 2 sector buffers of scratch space, and it is a design
00594     requirement of this code to operate on a single 512-byte scratch.
00595 
00596     If you are operating DOSFS over flash, you are strongly advised to implement a writeback
00597     cache in your physical I/O driver. This will speed up your code significantly and will
00598     also conserve power and flash write life.
00599 */
00600 NODEBUG uint32_t DFS_SetFAT( PVOLINFO volinfo, uint8_t* scratch, uint32_t* scratchcache, uint32_t cluster, uint32_t new_contents )
00601 {
00602     uint32_t offset, sector, result;
00603     if ( volinfo->filesystem == FAT12 )
00604     {
00605         offset = cluster + ( cluster / 2 );
00606         new_contents &= 0xfff;
00607     }
00608     else if ( volinfo->filesystem == FAT16 )
00609     {
00610         offset = cluster * 2;
00611         new_contents &= 0xffff;
00612     }
00613     else if ( volinfo->filesystem == FAT32 )
00614     {
00615         offset = cluster * 4;
00616         new_contents &= 0x0fffffff; /* FAT32 is really "FAT28"*/
00617     }
00618     else
00619         return DFS_ERRMISC;
00620 
00621     /* at this point, offset is the BYTE offset of the desired sector from the start*/
00622     /* of the FAT. Calculate the physical sector containing this FAT entry.*/
00623     sector = DFS_ldiv( offset, SECTOR_SIZE ).quot + volinfo->fat1;
00624 
00625     /* If this is not the same sector we last read, then read it into RAM*/
00626     if ( sector != *scratchcache )
00627     {
00628         if ( DFS_ReadSector( volinfo->unit, scratch, sector, 1 ) )
00629         {
00630             /* avoid anyone assuming that this cache value is still valid, which*/
00631             /* might cause disk corruption*/
00632             *scratchcache = 0;
00633             return DFS_ERRMISC;
00634         }
00635         *scratchcache = sector;
00636     }
00637 
00638     /* At this point, we "merely" need to extract the relevant entry.*/
00639     /* This is easy for FAT16 and FAT32, but a royal PITA for FAT12 as a single entry*/
00640     /* may span a sector boundary. The normal way around this is always to read two*/
00641     /* FAT sectors, but that luxury is (by design intent) unavailable to DOSFS.*/
00642     offset = DFS_ldiv( offset, SECTOR_SIZE ).rem;
00643 
00644     if ( volinfo->filesystem == FAT12 )
00645     {
00646 
00647         /* If this is an odd cluster, pre-shift the desired new contents 4 bits to*/
00648         /* make the calculations below simpler*/
00649         if ( cluster & 1 )
00650             new_contents = new_contents << 4;
00651 
00652         /* Special case for sector boundary*/
00653         if ( offset == SECTOR_SIZE - 1 )
00654         {
00655 
00656             /* Odd cluster: High 12 bits being set*/
00657             if ( cluster & 1 )
00658             {
00659                 scratch[offset] = ( scratch[offset] & 0x0f ) | new_contents & 0xf0;
00660             }
00661             /* Even cluster: Low 12 bits being set*/
00662             else
00663             {
00664                 scratch[offset] = new_contents & 0xff;
00665             }
00666             result = DFS_WriteSector( volinfo->unit, scratch, *scratchcache, 1 );
00667             /* mirror the FAT into copy 2*/
00668             if ( DFS_OK == result )
00669                 result = DFS_WriteSector( volinfo->unit, scratch, ( *scratchcache ) + volinfo->secperfat, 1 );
00670 
00671             /* If we wrote that sector OK, then read in the subsequent sector*/
00672             /* and poke the first byte with the remainder of this FAT entry.*/
00673             if ( DFS_OK == result )
00674             {
00675                 *scratchcache++;
00676                 result = DFS_ReadSector( volinfo->unit, scratch, *scratchcache, 1 );
00677                 if ( DFS_OK == result )
00678                 {
00679                     /* Odd cluster: High 12 bits being set*/
00680                     if ( cluster & 1 )
00681                     {
00682                         scratch[0] = new_contents & 0xff00;
00683                     }
00684                     /* Even cluster: Low 12 bits being set*/
00685                     else
00686                     {
00687                         scratch[0] = ( scratch[0] & 0xf0 ) | new_contents & 0x0f;
00688                     }
00689                     result = DFS_WriteSector( volinfo->unit, scratch, *scratchcache, 1 );
00690                     /* mirror the FAT into copy 2*/
00691                     if ( DFS_OK == result )
00692                         result = DFS_WriteSector( volinfo->unit, scratch, ( *scratchcache ) + volinfo->secperfat, 1 );
00693                 }
00694                 else
00695                 {
00696                     /* avoid anyone assuming that this cache value is still valid, which*/
00697                     /* might cause disk corruption*/
00698                     *scratchcache = 0;
00699                 }
00700             }
00701         } /* if (offset == SECTOR_SIZE - 1)*/
00702 
00703         /* Not a sector boundary. But we still have to worry about if it's an odd*/
00704         /* or even cluster number.*/
00705         else
00706         {
00707             /* Odd cluster: High 12 bits being set*/
00708             if ( cluster & 1 )
00709             {
00710                 scratch[offset] = ( scratch[offset] & 0x0f ) | new_contents & 0xf0;
00711                 scratch[offset + 1] = new_contents & 0xff00;
00712             }
00713             /* Even cluster: Low 12 bits being set*/
00714             else
00715             {
00716                 scratch[offset] = new_contents & 0xff;
00717                 scratch[offset + 1] = ( scratch[offset + 1] & 0xf0 ) | new_contents & 0x0f;
00718             }
00719             result = DFS_WriteSector( volinfo->unit, scratch, *scratchcache, 1 );
00720             /* mirror the FAT into copy 2*/
00721             if ( DFS_OK == result )
00722                 result = DFS_WriteSector( volinfo->unit, scratch, ( *scratchcache ) + volinfo->secperfat, 1 );
00723         }
00724     }
00725     else if ( volinfo->filesystem == FAT16 )
00726     {
00727         scratch[offset] = ( new_contents & 0xff );
00728         scratch[offset + 1] = ( new_contents & 0xff00 ) >> 8;
00729         result = DFS_WriteSector( volinfo->unit, scratch, *scratchcache, 1 );
00730         /* mirror the FAT into copy 2*/
00731         if ( DFS_OK == result )
00732             result = DFS_WriteSector( volinfo->unit, scratch, ( *scratchcache ) + volinfo->secperfat, 1 );
00733     }
00734     else if ( volinfo->filesystem == FAT32 )
00735     {
00736         scratch[offset] = ( new_contents & 0xff );
00737         scratch[offset + 1] = ( new_contents & 0xff00 ) >> 8;
00738         scratch[offset + 2] = ( new_contents & 0xff0000 ) >> 16;
00739         scratch[offset + 3] = ( scratch[offset + 3] & 0xf0 ) | ( ( new_contents & 0x0f000000 ) >> 24 );
00740         /* Note well from the above: Per Microsoft's guidelines we preserve the upper*/
00741         /* 4 bits of the FAT32 cluster value. It's unclear what these bits will be used*/
00742         /* for; in every example I've encountered they are always zero.*/
00743         result = DFS_WriteSector( volinfo->unit, scratch, *scratchcache, 1 );
00744         /* mirror the FAT into copy 2*/
00745         if ( DFS_OK == result )
00746             result = DFS_WriteSector( volinfo->unit, scratch, ( *scratchcache ) + volinfo->secperfat, 1 );
00747     }
00748     else
00749         result = DFS_ERRMISC;
00750 
00751     return result;
00752 }
00753 
00754 /*
00755     Convert a filename element from canonical (8.3) to directory entry (11) form
00756     src must point to the first non-separator character.
00757     dest must point to a 12-byte buffer.
00758 */
00759 NODEBUG uint8_t* DFS_CanonicalToDir( uint8_t* dest, uint8_t* src )
00760 {
00761     uint8_t* destptr = dest;
00762     vs32 c = '5';
00763 
00764     c = *src;
00765 
00766     DFS_memset( dest, ' ', 11 );
00767     dest[11] = 0;
00768 
00769     while ( *src && ( *src != DIR_SEPARATOR ) && ( destptr - dest < 11 ) )
00770     {
00771         if ( *src >= 'a' && *src <= 'z' )
00772         {
00773             *destptr++ = c = ( *src - 'a' ) + 'A';
00774             src++;
00775         }
00776         else if ( *src == '.' )
00777         {
00778             src++;
00779             destptr = dest + 8;
00780         }
00781         else
00782         {
00783             *destptr = c;
00784             *destptr++ = *src++;
00785         }
00786     }
00787 
00788     return dest;
00789 }
00790 
00791 /*
00792     Find the first unused FAT entry
00793     You must provide a scratch buffer for one sector (SECTOR_SIZE) and a populated VOLINFO
00794     Returns a FAT32 BAD_CLUSTER value for any error, otherwise the contents of the desired
00795     FAT entry.
00796     Returns FAT32 bad_sector (0x0ffffff7) if there is no free cluster available
00797 */
00798 NODEBUG uint32_t DFS_GetFreeFAT( PVOLINFO volinfo, uint8_t* scratch )
00799 {
00800     uint32_t i, result = 0xffffffff, scratchcache = 0;
00801 
00802     /* Search starts at cluster 2, which is the first usable cluster*/
00803     /* NOTE: This search can't terminate at a bad cluster, because there might*/
00804     /* legitimately be bad clusters on the disk.*/
00805     for ( i = 2; i < volinfo->numclusters; i++ )
00806     {
00807         result = DFS_GetFAT( volinfo, scratch, &scratchcache, i );
00808         if ( !result )
00809         {
00810             return i;
00811         }
00812     }
00813     return 0x0ffffff7;      /* Can't find a free cluster*/
00814 }
00815 
00816 
00817 /*
00818     Open a directory for enumeration by DFS_GetNextDirEnt
00819     You must supply a populated VOLINFO (see DFS_GetVolInfo)
00820     The empty string or a string containing only the directory separator are
00821     considered to be the root directory.
00822     Returns 0 OK, nonzero for any error.
00823 */
00824 NODEBUG uint32_t DFS_OpenDir( PVOLINFO volinfo, uint8_t* dirname, PDIRINFO dirinfo )
00825 {
00826     /* Default behavior is a regular search for existing entries*/
00827     dirinfo->flags = 0;
00828     u8 c = *dirname;
00829 
00830     /*  if (!DFS_strlen((u8 *) dirname) || (DFS_strlen((u8 *) dirname) == 1 && dirname[0] == DIR_SEPARATOR))   // YRT20080204*/
00831     if ( !my_strlen( ( u8* ) dirname ) || ( my_strlen( ( u8* ) dirname ) == 1 && dirname[0] == DIR_SEPARATOR ) )
00832     {
00833         if ( volinfo->filesystem == FAT32 )
00834         {
00835             dirinfo->currentcluster = volinfo->rootdir;
00836             dirinfo->currentsector = 0;
00837             dirinfo->currententry = 0;
00838 
00839             /* read first sector of directory*/
00840             return DFS_ReadSector( volinfo->unit, dirinfo->scratch, volinfo->dataarea + ( ( volinfo->rootdir - 2 ) * volinfo->secperclus ), 1 );
00841         }
00842         else
00843         {
00844             dirinfo->currentcluster = 0;
00845             dirinfo->currentsector = 0;
00846             dirinfo->currententry = 0;
00847 
00848             /* read first sector of directory*/
00849             return DFS_ReadSector( volinfo->unit, dirinfo->scratch, volinfo->rootdir, 1 );
00850         }
00851     }
00852 
00853     /* This is not the root directory. We need to find the start of this subdirectory.*/
00854     /* We do this by devious means, using our own companion function DFS_GetNext.*/
00855     else
00856     {
00857         uint8_t tmpfn[12];
00858         uint8_t* ptr = dirname;
00859         uint32_t result;
00860         DIRENT de;
00861 
00862         if ( volinfo->filesystem == FAT32 )
00863         {
00864             dirinfo->currentcluster = volinfo->rootdir;
00865             dirinfo->currentsector = 0;
00866             dirinfo->currententry = 0;
00867 
00868             /* read first sector of directory*/
00869             if ( DFS_ReadSector( volinfo->unit, dirinfo->scratch, volinfo->dataarea + ( ( volinfo->rootdir - 2 ) * volinfo->secperclus ), 1 ) )
00870                 return DFS_ERRMISC;
00871         }
00872         else
00873         {
00874             dirinfo->currentcluster = 0;
00875             dirinfo->currentsector = 0;
00876             dirinfo->currententry = 0;
00877 
00878             /* read first sector of directory*/
00879             if ( DFS_ReadSector( volinfo->unit, dirinfo->scratch, volinfo->rootdir, 1 ) )
00880                 return DFS_ERRMISC;
00881         }
00882 
00883         /* skip leading path separators*/
00884         while ( *ptr == DIR_SEPARATOR && *ptr )
00885             ptr++;
00886 
00887         /* Scan the path from left to right, finding the start cluster of each entry*/
00888         /* Observe that this code is inelegant, but obviates the need for recursion.*/
00889         while ( *ptr )
00890         {
00891 
00892             DFS_CanonicalToDir( tmpfn, ptr );
00893 
00894             de.name[0] = 0;
00895 
00896             do
00897             {
00898                 result = DFS_GetNext( volinfo, dirinfo, &de );
00899             }
00900             while ( !result && DFS_memcmp( de.name, tmpfn, 11 ) );
00901 
00902             if ( !DFS_memcmp( de.name, tmpfn, 11 ) && ( ( de.attr & ATTR_DIRECTORY ) == ATTR_DIRECTORY ) )
00903             {
00904                 if ( volinfo->filesystem == FAT32 )
00905                 {
00906                     dirinfo->currentcluster = ( uint32_t ) de.startclus_l_l |
00907                                               ( ( uint32_t ) de.startclus_l_h ) << 8 |
00908                                               ( ( uint32_t ) de.startclus_h_l ) << 16 |
00909                                               ( ( uint32_t ) de.startclus_h_h ) << 24;
00910                 }
00911                 else
00912                 {
00913                     dirinfo->currentcluster = ( uint32_t ) de.startclus_l_l |
00914                                               ( ( uint32_t ) de.startclus_l_h ) << 8;
00915                 }
00916                 dirinfo->currentsector = 0;
00917                 dirinfo->currententry = 0;
00918 
00919                 if ( DFS_ReadSector( volinfo->unit, dirinfo->scratch, volinfo->dataarea + ( ( dirinfo->currentcluster - 2 ) * volinfo->secperclus ), 1 ) )
00920                     return DFS_ERRMISC;
00921             }
00922             else if ( !DFS_memcmp( de.name, tmpfn, 11 ) && !( de.attr & ATTR_DIRECTORY ) )
00923                 return DFS_NOTFOUND;
00924 
00925             /* seek to next item in list*/
00926             while ( *ptr != DIR_SEPARATOR && *ptr )
00927                 ptr++;
00928             if ( *ptr == DIR_SEPARATOR )
00929                 ptr++;
00930         }
00931 
00932         if ( !dirinfo->currentcluster )
00933             return DFS_NOTFOUND;
00934     }
00935     return DFS_OK;
00936 }
00937 
00938 /*
00939     Get next entry in opened directory structure. Copies fields into the dirent
00940     structure, updates dirinfo. Note that it is the _caller's_ responsibility to
00941     handle the '.' and '..' entries.
00942     A deleted file will be returned as a NULL entry (first u8 of filename=0)
00943     by this code. Filenames beginning with 0x05 will be translated to 0xE5
00944     automatically. Long file name entries will be returned as NULL.
00945     returns DFS_EOF if there are no more entries, DFS_OK if this entry is valid,
00946     or DFS_ERRMISC for a media error
00947 */
00948 NODEBUG uint32_t DFS_GetNext( PVOLINFO volinfo, PDIRINFO dirinfo, PDIRENT dirent )
00949 {
00950     uint32_t tempint;    // required by DFS_GetFAT
00951 
00952     /* Do we need to read the next sector of the directory?*/
00953     if ( dirinfo->currententry >= SECTOR_SIZE / sizeof( DIRENT ) )
00954     {
00955         dirinfo->currententry = 0;
00956         dirinfo->currentsector++;
00957 
00958         /* Root directory; special case handling */
00959         /* Note that currentcluster will only ever be zero if both:*/
00960         /* (a) this is the root directory, and*/
00961         /* (b) we are on a FAT12/16 volume, where the root dir can't be expanded*/
00962         if ( dirinfo->currentcluster == 0 )
00963         {
00964             /* Trying to read past end of root directory?*/
00965             if ( dirinfo->currentsector * ( SECTOR_SIZE / sizeof( DIRENT ) ) >= volinfo->rootentries )
00966                 return DFS_EOF;
00967 
00968             /* Otherwise try to read the next sector*/
00969             if ( DFS_ReadSector( volinfo->unit, dirinfo->scratch, volinfo->rootdir + dirinfo->currentsector, 1 ) )
00970                 return DFS_ERRMISC;
00971         }
00972 
00973         /* Normal handling*/
00974         else
00975         {
00976             if ( dirinfo->currentsector >= volinfo->secperclus )
00977             {
00978                 dirinfo->currentsector = 0;
00979                 if ( ( dirinfo->currentcluster >= 0xff7 &&  volinfo->filesystem == FAT12 ) ||
00980                         ( dirinfo->currentcluster >= 0xfff7 &&  volinfo->filesystem == FAT16 ) ||
00981                         ( dirinfo->currentcluster >= 0x0ffffff7 &&  volinfo->filesystem == FAT32 ) )
00982                 {
00983 
00984                     /* We are at the end of the directory chain. If this is a normal*/
00985                     /* find operation, we should indicate that there is nothing more*/
00986                     /* to see.*/
00987                     if ( !( dirinfo->flags & DFS_DI_BLANKENT ) )
00988                         return DFS_EOF;
00989 
00990                     /* On the other hand, if this is a "find free entry" search,*/
00991                     /* we need to tell the caller to allocate a new cluster*/
00992                     else
00993                         return DFS_ALLOCNEW;
00994                 }
00995                 dirinfo->currentcluster = DFS_GetFAT( volinfo, dirinfo->scratch, &tempint, dirinfo->currentcluster );
00996             }
00997             if ( DFS_ReadSector( volinfo->unit, dirinfo->scratch, volinfo->dataarea + ( ( dirinfo->currentcluster - 2 ) * volinfo->secperclus ) + dirinfo->currentsector, 1 ) )
00998                 return DFS_ERRMISC;
00999         }
01000     }
01001 
01002     DFS_memcpy( dirent, &( ( ( PDIRENT ) dirinfo->scratch )[dirinfo->currententry] ), sizeof( DIRENT ) );
01003 
01004     if ( dirent->name[0] == 0 )        /* no more files in this directory*/
01005     {
01006         /* If this is a "find blank" then we can reuse this name.*/
01007         if ( dirinfo->flags & DFS_DI_BLANKENT )
01008         {
01009             //NTRF: Invalid indexing! Current must be incremented proir to returning OK
01010             dirinfo->currententry++;
01011             return DFS_OK;
01012         }
01013         else
01014             return DFS_EOF;
01015     }
01016 
01017     if ( dirent->name[0] == 0xe5 )  /* handle deleted file entries*/
01018         dirent->name[0] = 0;
01019     else if ( ( ( dirent->attr & ATTR_LONG_NAME ) == ATTR_LONG_NAME ) &&
01020               !( dirinfo->flags & DFS_DI_BLANKENT ) ) //NTRF: don't replace longnames with new files
01021         dirent->name[0] = 0;
01022     else if ( dirent->name[0] == 0x05 )  /* handle kanji filenames beginning with 0xE5*/
01023         dirent->name[0] = 0xe5;
01024 
01025     dirinfo->currententry++;
01026 
01027     return DFS_OK;
01028 }
01029 
01030 /*
01031     INTERNAL
01032     Find a free directory entry in the directory specified by path
01033     This function MAY cause a disk write if it is necessary to extend the directory
01034     size.
01035     Note - di.scratch must be preinitialized to point to a sector scratch buffer
01036     de is a scratch structure
01037     Returns DFS_ERRMISC if a new entry could not be located or created
01038     de is updated with the same return information you would expect from DFS_GetNext
01039 */
01040 NODEBUG uint32_t DFS_GetFreeDirEnt( PVOLINFO volinfo, uint8_t* path, PDIRINFO di, PDIRENT de )
01041 {
01042     uint32_t tempclus, i;
01043 
01044     if ( DFS_OpenDir( volinfo, path, di ) )
01045         return DFS_NOTFOUND;
01046 
01047     /* Set "search for empty" flag so DFS_GetNext knows what we're doing*/
01048     di->flags |= DFS_DI_BLANKENT;
01049 
01050     /* We seek through the directory looking for an empty entry*/
01051     /* Note we are reusing tempclus as a temporary result holder.*/
01052     tempclus = 0;
01053     do
01054     {
01055         tempclus = DFS_GetNext( volinfo, di, de );
01056 
01057         /* Empty entry found*/
01058         if ( tempclus == DFS_OK && ( !de->name[0] ) )
01059         {
01060             return DFS_OK;
01061         }
01062 
01063         /* End of root directory reached*/
01064         else if ( tempclus == DFS_EOF )
01065             return DFS_ERRMISC;
01066 
01067         else if ( tempclus == DFS_ALLOCNEW )
01068         {
01069             tempclus = DFS_GetFreeFAT( volinfo, di->scratch );
01070             if ( tempclus == 0x0ffffff7 )
01071                 return DFS_ERRMISC;
01072 
01073             /* write out zeroed sectors to the new cluster*/
01074             DFS_memset( di->scratch, 0, SECTOR_SIZE );
01075             for ( i = 0; i < volinfo->secperclus; i++ )
01076             {
01077                 if ( DFS_WriteSector( volinfo->unit, di->scratch, volinfo->dataarea + ( ( tempclus - 2 ) * volinfo->secperclus ) + i, 1 ) )
01078                     return DFS_ERRMISC;
01079             }
01080             /* Point old end cluster to newly allocated cluster*/
01081             i = 0;
01082             DFS_SetFAT( volinfo, di->scratch, &i, di->currentcluster, tempclus );
01083 
01084             /* Update DIRINFO so caller knows where to place the new file           */
01085             di->currentcluster = tempclus;
01086             di->currentsector = 0;
01087             di->currententry = 1;   /* since the code coming after this expects to subtract 1*/
01088 
01089             /* Mark newly allocated cluster as end of chain         */
01090             switch ( volinfo->filesystem )
01091             {
01092             case FAT12:     tempclus = 0xff8;   break;
01093             case FAT16:     tempclus = 0xfff8;  break;
01094             case FAT32:     tempclus = 0x0ffffff8;  break;
01095             default:        return DFS_ERRMISC;
01096             }
01097             DFS_SetFAT( volinfo, di->scratch, &i, di->currentcluster, tempclus );
01098         }
01099     }
01100     while ( !tempclus );
01101 
01102     /* We shouldn't get here*/
01103     return DFS_ERRMISC;
01104 }
01105 
01106 /*
01107     Open a file for reading or writing. You supply populated VOLINFO, a path to the file,
01108     mode (DFS_READ or DFS_WRITE) and an empty fileinfo structure. You also need to
01109     provide a pointer to a sector-sized scratch buffer.
01110     Returns various DFS_* error states. If the result is DFS_OK, fileinfo can be used
01111     to access the file from this point on.
01112 */
01113 NODEBUG uint32_t DFS_OpenFile( PVOLINFO volinfo, uint8_t* path, uint8_t mode, uint8_t* scratch, PFILEINFO fileinfo )
01114 {
01115     uint8_t tmppath[MAX_PATH];
01116     uint8_t filename[12];
01117     uint8_t* p;
01118     DIRINFO di;
01119     DIRENT de;
01120     uint32_t dircluster;
01121 
01122     /* larwe 2006-09-16 +1 zero out file structure*/
01123     DFS_memset( fileinfo, 0, sizeof( FILEINFO ) );
01124 
01125     /* save access mode*/
01126     fileinfo->mode = mode;
01127 
01128     /* Get a local copy of the path. If it's longer than MAX_PATH, abort.*/
01129     DFS_strncpy( ( u8* ) tmppath, ( u8* ) path, MAX_PATH );
01130     tmppath[MAX_PATH - 1] = 0;
01131     if ( DFS_strcmp( ( u8* ) path, ( u8* ) tmppath ) )
01132     {
01133         return DFS_PATHLEN;
01134     }
01135 
01136     /* strip leading path separators*/
01137     while ( tmppath[0] == DIR_SEPARATOR )
01138         DFS_strcpy( ( u8* ) tmppath, ( u8* ) tmppath + 1 );
01139 
01140     /* Parse filename off the end of the supplied path*/
01141     p = tmppath;
01142     while ( *( p++ ) );
01143 
01144     p--;
01145     while ( p > tmppath && *p != DIR_SEPARATOR ) /* larwe 9/16/06 ">=" to ">" bugfix*/
01146         p--;
01147     if ( *p == DIR_SEPARATOR )
01148         p++;
01149 
01150     DFS_CanonicalToDir( filename, p );
01151 
01152     if ( p > tmppath )
01153         p--;
01154     if ( *p == DIR_SEPARATOR || p == tmppath ) // larwe 9/16/06 +"|| p == tmppath" bugfix
01155         *p = 0;
01156 
01157     /* At this point, if our path was MYDIR/MYDIR2/FILE.EXT, filename = "FILE    EXT" and*/
01158     /* tmppath = "MYDIR/MYDIR2".*/
01159     di.scratch = scratch;
01160     dircluster = di.currentcluster;
01161 
01162     if ( DFS_OpenDir( volinfo, tmppath, &di ) )
01163         return DFS_NOTFOUND;
01164 
01165     while ( !DFS_GetNext( volinfo, &di, &de ) )
01166     {
01167         if ( !DFS_memcmp( de.name, filename, 11 ) )
01168         {
01169             /* You can't use this function call to open a directory.*/
01170             //NTRF: allows to create directories
01171             if ( ( de.attr & ATTR_DIRECTORY ) && ( mode != DFS_CREATEDIR ) )
01172                 return DFS_NOTFOUND;
01173 
01174             fileinfo->volinfo = volinfo;
01175             fileinfo->pointer = 0;
01176             /* The reason we store this extra info about the file is so that we can*/
01177             /* speedily update the file size, modification date, etc. on a file that is*/
01178             /* opened for writing.*/
01179             if ( di.currentcluster == 0 )
01180                 fileinfo->dirsector = volinfo->rootdir + di.currentsector;
01181             else
01182                 fileinfo->dirsector = volinfo->dataarea + ( ( di.currentcluster - 2 ) * volinfo->secperclus ) + di.currentsector;
01183             fileinfo->diroffset = di.currententry - 1;
01184             if ( volinfo->filesystem == FAT32 )
01185             {
01186                 fileinfo->cluster = ( uint32_t ) de.startclus_l_l |
01187                                     ( ( uint32_t ) de.startclus_l_h ) << 8 |
01188                                     ( ( uint32_t ) de.startclus_h_l ) << 16 |
01189                                     ( ( uint32_t ) de.startclus_h_h ) << 24;
01190             }
01191             else
01192             {
01193                 fileinfo->cluster = ( uint32_t ) de.startclus_l_l |
01194                                     ( ( uint32_t ) de.startclus_l_h ) << 8;
01195             }
01196             fileinfo->firstcluster = fileinfo->cluster;
01197             fileinfo->filelen = ( uint32_t ) de.filesize_0 |
01198                                 ( ( uint32_t ) de.filesize_1 ) << 8 |
01199                                 ( ( uint32_t ) de.filesize_2 ) << 16 |
01200                                 ( ( uint32_t ) de.filesize_3 ) << 24;
01201 
01202             return DFS_OK;
01203         }
01204     }
01205 
01206     /* At this point, we KNOW the file does not exist. If the file was opened*/
01207     /* with write access, we can create it.*/
01208     if ( mode & DFS_WRITE )
01209     {
01210         uint32_t cluster, temp;
01211 
01212         /* Locate or create a directory entry for this file*/
01213         if ( DFS_OK != DFS_GetFreeDirEnt( volinfo, tmppath, &di, &de ) )
01214             return DFS_ERRMISC;
01215 
01216         /* put sane values in the directory entry*/
01217         DFS_memset( &de, 0, sizeof( de ) );
01218         DFS_memcpy( de.name, filename, 11 );
01219         de.crttime_l = 0x20;    /* 01:01:00am, Jan 1, 2006.*/
01220         de.crttime_h = 0x08;
01221         de.crtdate_l = 0x11;
01222         de.crtdate_h = 0x34;
01223         de.lstaccdate_l = 0x11;
01224         de.lstaccdate_h = 0x34;
01225         de.wrttime_l = 0x20;
01226         de.wrttime_h = 0x08;
01227         de.wrtdate_l = 0x11;
01228         de.wrtdate_h = 0x34;
01229 
01230         //NTRF: create directory
01231         if ( mode == DFS_CREATEDIR ) de.attr |= ATTR_DIRECTORY;
01232 
01233         /* allocate a starting cluster for the directory entry*/
01234         cluster = DFS_GetFreeFAT( volinfo, scratch );
01235 
01236         de.startclus_l_l = cluster & 0xff;
01237         de.startclus_l_h = ( cluster & 0xff00 ) >> 8;
01238         de.startclus_h_l = ( cluster & 0xff0000 ) >> 16;
01239         de.startclus_h_h = ( cluster & 0xff000000 ) >> 24;
01240 
01241         /* update FILEINFO for our caller's sake*/
01242         fileinfo->volinfo = volinfo;
01243         fileinfo->pointer = 0;
01244         /* The reason we store this extra info about the file is so that we can*/
01245         /* speedily update the file size, modification date, etc. on a file that is*/
01246         /* opened for writing.*/
01247         if ( di.currentcluster == 0 )
01248             fileinfo->dirsector = volinfo->rootdir + di.currentsector;
01249         else
01250             fileinfo->dirsector = volinfo->dataarea + ( ( di.currentcluster - 2 ) * volinfo->secperclus ) + di.currentsector;
01251         fileinfo->diroffset = di.currententry - 1;
01252         fileinfo->cluster = cluster;
01253         fileinfo->firstcluster = cluster;
01254         fileinfo->filelen = 0;
01255 
01256         /* write the directory entry*/
01257         /* note that we no longer have the sector containing the directory entry,*/
01258         /* tragically, so we have to re-read it*/
01259         if ( DFS_ReadSector( volinfo->unit, scratch, fileinfo->dirsector, 1 ) )
01260             return DFS_ERRMISC;
01261         DFS_memcpy( &( ( ( PDIRENT ) scratch )[di.currententry - 1] ), &de, sizeof( DIRENT ) );
01262         if ( DFS_WriteSector( volinfo->unit, scratch, fileinfo->dirsector, 1 ) )
01263             return DFS_ERRMISC;
01264 
01265         /* Mark newly allocated cluster as end of chain            */
01266         switch ( volinfo->filesystem )
01267         {
01268         case FAT12:        cluster = 0xff8;    break;
01269         case FAT16:        cluster = 0xfff8;    break;
01270         case FAT32:        cluster = 0x0ffffff8;    break;
01271         default:        return DFS_ERRMISC;
01272         }
01273         temp = 0;
01274         DFS_SetFAT( volinfo, scratch, &temp, fileinfo->cluster, cluster );
01275 
01276         //Fill new directory with required info
01277         if ( mode == DFS_CREATEDIR )
01278         {
01279             if ( dircluster <= 2 ) //Root
01280                 dircluster = 0;
01281 
01282             uint32_t startsector = volinfo->dataarea + ( ( fileinfo->cluster - 2 ) * volinfo->secperclus );
01283             uint32_t endsector = startsector + volinfo->secperclus - 1;
01284 
01285             DFS_memset( scratch, 0, SECTOR_SIZE );
01286 
01287             for ( ; endsector > startsector; endsector -= 1 )
01288                 DFS_WriteSector( volinfo->unit, scratch, endsector, 1 );
01289 
01290             DFS_memcpy( &( de.name ), ".          ", 11 );
01291             de.filesize_0 = 0;
01292             de.filesize_1 = 0;
01293             de.filesize_2 = 0;
01294             de.filesize_3 = 0;
01295             DFS_memcpy( scratch, &de, sizeof( DIRENT ) );
01296 
01297             DFS_memcpy( &( de.name ), "..         ", 11 );
01298             de.startclus_l_l = dircluster & 0xff;
01299             de.startclus_l_h = ( dircluster & 0xff00 ) >> 8;
01300             de.startclus_h_l = ( dircluster & 0xff0000 ) >> 16;
01301             de.startclus_h_h = ( dircluster & 0xff000000 ) >> 24;
01302 
01303             DFS_memcpy( scratch + sizeof( DIRENT ), &de, sizeof( DIRENT ) );
01304 
01305             DFS_WriteSector( volinfo->unit, scratch, startsector, 1 );
01306         }
01307 
01308         return DFS_OK;
01309     }
01310 
01311     return DFS_NOTFOUND;
01312 }
01313 
01314 
01315 /*
01316     Read an open file
01317     You must supply a prepopulated FILEINFO as provided by DFS_OpenFile, and a
01318     pointer to a SECTOR_SIZE scratch buffer.
01319     Note that returning DFS_EOF is not an error condition. This function updates the
01320     successcount field with the number of bytes actually read.
01321 */
01322 NODEBUG uint32_t DFS_ReadFile( PFILEINFO fileinfo, uint8_t* scratch, uint8_t* buffer, uint32_t* successcount, uint32_t len )
01323 {
01324     uint32_t remain;
01325     uint32_t result = DFS_OK;
01326     uint32_t sector;
01327     uint32_t bytesread;
01328 
01329     /* Don't try to read past EOF*/
01330     if ( len > fileinfo->filelen - fileinfo->pointer )
01331         len = fileinfo->filelen - fileinfo->pointer;
01332 
01333     remain = len;
01334     *successcount = 0;
01335 
01336     while ( remain && result == DFS_OK )
01337     {
01338         /* This is a bit complicated. The sector we want to read is addressed at a cluster*/
01339         /* granularity by the fileinfo->cluster member. The file pointer tells us how many*/
01340         /* extra sectors to add to that number.*/
01341         sector = fileinfo->volinfo->dataarea +
01342                  ( ( fileinfo->cluster - 2 ) * fileinfo->volinfo->secperclus ) +
01343                  DFS_div( DFS_div( fileinfo->pointer, fileinfo->volinfo->secperclus * SECTOR_SIZE ).rem, SECTOR_SIZE ).quot;
01344 
01345         /* Case 1 - File pointer is not on a sector boundary*/
01346         if ( DFS_div( fileinfo->pointer, SECTOR_SIZE ).rem )
01347         {
01348             uint16_t tempreadsize;
01349 
01350             /* We always have to go through scratch in this case*/
01351             result = DFS_ReadSector( fileinfo->volinfo->unit, scratch, sector, 1 );
01352 
01353             /* This is the number of bytes that we actually care about in the sector*/
01354             /* just read.*/
01355             tempreadsize = SECTOR_SIZE - ( DFS_div( fileinfo->pointer, SECTOR_SIZE ).rem );
01356 
01357             /* Case 1A - We want the entire remainder of the sector. After this*/
01358             /* point, all passes through the read loop will be aligned on a sector*/
01359             /* boundary, which allows us to go through the optimal path 2A below.*/
01360             if ( remain >= tempreadsize )
01361             {
01362                 DFS_memcpy( buffer, scratch + ( SECTOR_SIZE - tempreadsize ), tempreadsize );
01363                 bytesread = tempreadsize;
01364                 buffer += tempreadsize;
01365                 fileinfo->pointer += tempreadsize;
01366                 remain -= tempreadsize;
01367             }
01368             /* Case 1B - This read concludes the file read operation*/
01369             else
01370             {
01371                 DFS_memcpy( buffer, scratch + ( SECTOR_SIZE - tempreadsize ), remain );
01372 
01373                 buffer += remain;
01374                 fileinfo->pointer += remain;
01375                 bytesread = remain;
01376                 remain = 0;
01377             }
01378         }
01379         /* Case 2 - File pointer is on sector boundary*/
01380         else
01381         {
01382             /* Case 2A - We have at least one more full sector to read and don't have*/
01383             /* to go through the scratch buffer. You could insert optimizations here to*/
01384             /* read multiple sectors at a time, if you were thus inclined (note that*/
01385             /* the maximum multi-read you could perform is a single cluster, so it would*/
01386             /* be advantageous to have code similar to case 1A above that would round the*/
01387             /* pointer to a cluster boundary the first pass through, so all subsequent*/
01388             /* [large] read requests would be able to go a cluster at a time).*/
01389             if ( remain >= SECTOR_SIZE )
01390             {
01391                 result = DFS_ReadSector( fileinfo->volinfo->unit, buffer, sector, 1 );
01392                 remain -= SECTOR_SIZE;
01393                 buffer += SECTOR_SIZE;
01394                 fileinfo->pointer += SECTOR_SIZE;
01395                 bytesread = SECTOR_SIZE;
01396             }
01397             /* Case 2B - We are only reading a partial sector*/
01398             else
01399             {
01400                 result = DFS_ReadSector( fileinfo->volinfo->unit, scratch, sector, 1 );
01401                 DFS_memcpy( buffer, scratch, remain );
01402                 buffer += remain;
01403                 fileinfo->pointer += remain;
01404                 bytesread = remain;
01405                 remain = 0;
01406             }
01407         }
01408 
01409         *successcount += bytesread;
01410 
01411         /* check to see if we stepped over a cluster boundary*/
01412         if ( DFS_div( fileinfo->pointer - bytesread, fileinfo->volinfo->secperclus * SECTOR_SIZE ).quot !=
01413                 DFS_div( fileinfo->pointer, fileinfo->volinfo->secperclus * SECTOR_SIZE ).quot )
01414         {
01415             /* An act of minor evil - we use bytesread as a scratch integer, knowing that*/
01416             /* its value is not used after updating *successcount above*/
01417             bytesread = 0;
01418             if ( ( ( fileinfo->volinfo->filesystem == FAT12 ) && ( fileinfo->cluster >= 0xff8 ) ) ||
01419                     ( ( fileinfo->volinfo->filesystem == FAT16 ) && ( fileinfo->cluster >= 0xfff8 ) ) ||
01420                     ( ( fileinfo->volinfo->filesystem == FAT32 ) && ( fileinfo->cluster >= 0x0ffffff8 ) ) )
01421                 result = DFS_EOF;
01422             else
01423                 fileinfo->cluster = DFS_GetFAT( fileinfo->volinfo, scratch, &bytesread, fileinfo->cluster );
01424         }
01425     }
01426 
01427     return result;
01428 }
01429 
01430 /*
01431     Seek file pointer to a given position
01432     This function does not return status - refer to the fileinfo->pointer value
01433     to see where the pointer wound up.
01434     Requires a SECTOR_SIZE scratch buffer
01435 */
01436 NODEBUG void DFS_Seek( PFILEINFO fileinfo, uint32_t offset, uint8_t* scratch )
01437 {
01438     uint32_t tempint;
01439 
01440     /* larwe 9/16/06 bugfix split case 0a/0b and changed fallthrough handling*/
01441     /* Case 0a - Return immediately for degenerate case*/
01442     if ( offset == fileinfo->pointer )
01443     {
01444         return;
01445     }
01446 
01447     /* Case 0b - Don't allow the user to seek past the end of the file*/
01448     if ( offset > fileinfo->filelen )
01449     {
01450         offset = fileinfo->filelen;
01451         // NOTE NO RETURN HERE!
01452     }
01453 
01454     /* Case 1 - Simple rewind to start*/
01455     /* Note _intentional_ fallthrough from Case 0b above*/
01456     if ( offset == 0 )
01457     {
01458         fileinfo->cluster = fileinfo->firstcluster;
01459         fileinfo->pointer = 0;
01460         return;     /* larwe 9/16/06 +1 bugfix*/
01461     }
01462     /* Case 2 - Seeking backwards. Need to reset and seek forwards*/
01463     else if ( offset < fileinfo->pointer )
01464     {
01465         fileinfo->cluster = fileinfo->firstcluster;
01466         fileinfo->pointer = 0;
01467         /* NOTE NO RETURN HERE!*/
01468     }
01469 
01470     /* Case 3 - Seeking forwards*/
01471     /* Note _intentional_ fallthrough from Case 2 above*/
01472 
01473     /* Case 3a - Seek size does not cross cluster boundary - */
01474     /* very simple case*/
01475     /* larwe 9/16/06 changed .rem to .quot in both div calls, bugfix*/
01476     if ( DFS_div( fileinfo->pointer, fileinfo->volinfo->secperclus * SECTOR_SIZE ).quot ==
01477             DFS_div( fileinfo->pointer + offset, fileinfo->volinfo->secperclus * SECTOR_SIZE ).quot )
01478     {
01479         fileinfo->pointer = offset;
01480     }
01481     /* Case 3b - Seeking across cluster boundary(ies)*/
01482     else
01483     {
01484         /* round file pointer down to cluster boundary*/
01485         fileinfo->pointer = DFS_div( fileinfo->pointer, fileinfo->volinfo->secperclus * SECTOR_SIZE ).quot *
01486                             fileinfo->volinfo->secperclus * SECTOR_SIZE;
01487 
01488         /* seek by clusters*/
01489         /* larwe 9/30/06 bugfix changed .rem to .quot in both div calls*/
01490         while ( DFS_div( fileinfo->pointer, fileinfo->volinfo->secperclus * SECTOR_SIZE ).quot !=
01491                 DFS_div( offset, fileinfo->volinfo->secperclus * SECTOR_SIZE ).quot )  //correct calculation of actual cluster
01492         {
01493             /* DFS_div(fileinfo->pointer + offset, fileinfo->volinfo->secperclus * SECTOR_SIZE).quot) {*/
01494             /* if you want to set the filepointer  beyond a cluster limit this line crashes the whole system*/
01495             /* adding the offset to the filepointer causes the while to loop infinitely */
01496 
01497 
01498             fileinfo->cluster = DFS_GetFAT( fileinfo->volinfo, scratch, &tempint, fileinfo->cluster );
01499             /* Abort if there was an error*/
01500             if ( fileinfo->cluster == 0x0ffffff7 )
01501             {
01502                 fileinfo->pointer = 0;
01503                 fileinfo->cluster = fileinfo->firstcluster;
01504                 return;
01505             }
01506             fileinfo->pointer += SECTOR_SIZE * fileinfo->volinfo->secperclus;
01507         }
01508 
01509         /* since we know the cluster is right, we have no more work to do*/
01510         fileinfo->pointer = offset;
01511     }
01512 }
01513 
01514 /*
01515     Delete a file
01516     scratch must point to a sector-sized buffer
01517 */
01518 NODEBUG uint32_t DFS_UnlinkFile( PVOLINFO volinfo, uint8_t* path, uint8_t* scratch )
01519 {
01520     PDIRENT de = ( PDIRENT ) scratch;
01521     FILEINFO fi;
01522     uint32_t cache = 0;
01523     uint32_t tempclus;
01524 
01525     /* DFS_OpenFile gives us all the information we need to delete it*/
01526     if ( DFS_OK != DFS_OpenFile( volinfo, path, DFS_READ, scratch, &fi ) )
01527         return DFS_NOTFOUND;
01528 
01529     /* First, read the directory sector and delete that entry*/
01530     if ( DFS_ReadSector( volinfo->unit, scratch, fi.dirsector, 1 ) )
01531         return DFS_ERRMISC;
01532     ( ( PDIRENT ) scratch )[fi.diroffset].name[0] = 0xe5;
01533     if ( DFS_WriteSector( volinfo->unit, scratch, fi.dirsector, 1 ) )
01534         return DFS_ERRMISC;
01535 
01536     /* Now follow the cluster chain to free the file space*/
01537     while ( !( ( volinfo->filesystem == FAT12 && fi.firstcluster >= 0x0ff7 ) ||
01538                ( volinfo->filesystem == FAT16 && fi.firstcluster >= 0xfff7 ) ||
01539                ( volinfo->filesystem == FAT32 && fi.firstcluster >= 0x0ffffff7 ) ) )
01540     {
01541         tempclus = fi.firstcluster;
01542 
01543         fi.firstcluster = DFS_GetFAT( volinfo, scratch, &cache, fi.firstcluster );
01544         DFS_SetFAT( volinfo, scratch, &cache, tempclus, 0 );
01545 
01546     }
01547     return DFS_OK;
01548 }
01549 
01550 
01551 /*
01552     Write an open file
01553     You must supply a prepopulated FILEINFO as provided by DFS_OpenFile, and a
01554     pointer to a SECTOR_SIZE scratch buffer.
01555     This function updates the successcount field with the number of bytes actually written.
01556 */
01557 NODEBUG uint32_t DFS_WriteFile( PFILEINFO fileinfo, uint8_t* scratch, uint8_t* buffer, uint32_t* successcount, uint32_t len )
01558 {
01559     uint32_t remain;
01560     uint32_t result = DFS_OK;
01561     uint32_t sector;
01562     uint32_t byteswritten;
01563 
01564     /* Don't allow writes to a file that's open as readonly*/
01565     if ( !( fileinfo->mode & DFS_WRITE ) )
01566         return DFS_ERRMISC;
01567 
01568     remain = len;
01569     *successcount = 0;
01570 
01571     while ( remain && result == DFS_OK )
01572     {
01573         /* This is a bit complicated. The sector we want to read is addressed at a cluster*/
01574         /* granularity by the fileinfo->cluster member. The file pointer tells us how many*/
01575         /* extra sectors to add to that number.*/
01576         sector = fileinfo->volinfo->dataarea +
01577                  ( ( fileinfo->cluster - 2 ) * fileinfo->volinfo->secperclus ) +
01578                  DFS_div( DFS_div( fileinfo->pointer, fileinfo->volinfo->secperclus * SECTOR_SIZE ).rem, SECTOR_SIZE ).quot;
01579 
01580         /* Case 1 - File pointer is not on a sector boundary*/
01581         if ( DFS_div( fileinfo->pointer, SECTOR_SIZE ).rem )
01582         {
01583             uint16_t tempsize;
01584 
01585             /* We always have to go through scratch in this case*/
01586             result = DFS_ReadSector( fileinfo->volinfo->unit, scratch, sector, 1 );
01587 
01588             /* This is the number of bytes that we don't want to molest in the*/
01589             /* scratch sector just read.*/
01590             tempsize = DFS_div( fileinfo->pointer, SECTOR_SIZE ).rem;
01591 
01592             /* Case 1A - We are writing the entire remainder of the sector. After*/
01593             /* this point, all passes through the read loop will be aligned on a*/
01594             /* sector boundary, which allows us to go through the optimal path*/
01595             /* 2A below.*/
01596             if ( remain >= SECTOR_SIZE - tempsize )
01597             {
01598                 DFS_memcpy( scratch + tempsize, buffer, SECTOR_SIZE - tempsize );
01599                 if ( !result )
01600                     result = DFS_WriteSector( fileinfo->volinfo->unit, scratch, sector, 1 );
01601 
01602                 byteswritten = SECTOR_SIZE - tempsize;
01603                 buffer += SECTOR_SIZE - tempsize;
01604                 fileinfo->pointer += SECTOR_SIZE - tempsize;
01605                 if ( fileinfo->filelen < fileinfo->pointer )
01606                 {
01607                     fileinfo->filelen = fileinfo->pointer;
01608                 }
01609                 remain -= SECTOR_SIZE - tempsize;
01610             }
01611             /* Case 1B - This concludes the file write operation*/
01612             else
01613             {
01614                 DFS_memcpy( scratch + tempsize, buffer, remain );
01615                 if ( !result )
01616                     result = DFS_WriteSector( fileinfo->volinfo->unit, scratch, sector, 1 );
01617 
01618                 buffer += remain;
01619                 fileinfo->pointer += remain;
01620                 if ( fileinfo->filelen < fileinfo->pointer )
01621                 {
01622                     fileinfo->filelen = fileinfo->pointer;
01623                 }
01624                 byteswritten = remain;
01625                 remain = 0;
01626             }
01627         } /* case 1*/
01628         /* Case 2 - File pointer is on sector boundary*/
01629         else
01630         {
01631             /* Case 2A - We have at least one more full sector to write and don't have*/
01632             /* to go through the scratch buffer. You could insert optimizations here to*/
01633             /* write multiple sectors at a time, if you were thus inclined. Refer to*/
01634             /* similar notes in DFS_ReadFile.*/
01635             if ( remain >= SECTOR_SIZE )
01636             {
01637                 result = DFS_WriteSector( fileinfo->volinfo->unit, buffer, sector, 1 );
01638                 remain -= SECTOR_SIZE;
01639                 buffer += SECTOR_SIZE;
01640                 fileinfo->pointer += SECTOR_SIZE;
01641                 if ( fileinfo->filelen < fileinfo->pointer )
01642                 {
01643                     fileinfo->filelen = fileinfo->pointer;
01644                 }
01645                 byteswritten = SECTOR_SIZE;
01646             }
01647             /* Case 2B - We are only writing a partial sector and potentially need to*/
01648             /* go through the scratch buffer.*/
01649             else
01650             {
01651                 /* If the current file pointer is not yet at or beyond the file*/
01652                 /* length, we are writing somewhere in the middle of the file and*/
01653                 /* need to load the original sector to do a read-modify-write.*/
01654                 if ( fileinfo->pointer < fileinfo->filelen )
01655                 {
01656                     result = DFS_ReadSector( fileinfo->volinfo->unit, scratch, sector, 1 );
01657                     if ( !result )
01658                     {
01659                         DFS_memcpy( scratch, buffer, remain );
01660                         result = DFS_WriteSector( fileinfo->volinfo->unit, scratch, sector, 1 );
01661                     }
01662                 }
01663                 else
01664                 {
01665                     result = DFS_WriteSector( fileinfo->volinfo->unit, buffer, sector, 1 );
01666                 }
01667 
01668                 buffer += remain;
01669                 fileinfo->pointer += remain;
01670                 if ( fileinfo->filelen < fileinfo->pointer )
01671                 {
01672                     fileinfo->filelen = fileinfo->pointer;
01673                 }
01674                 byteswritten = remain;
01675                 remain = 0;
01676             }
01677         }
01678 
01679         *successcount += byteswritten;
01680 
01681         /* check to see if we stepped over a cluster boundary*/
01682         if ( DFS_div( fileinfo->pointer - byteswritten, fileinfo->volinfo->secperclus * SECTOR_SIZE ).quot !=
01683                 DFS_div( fileinfo->pointer, fileinfo->volinfo->secperclus * SECTOR_SIZE ).quot )
01684         {
01685             uint32_t lastcluster;
01686 
01687             /* We've transgressed into another cluster. If we were already at EOF,*/
01688             /* we need to allocate a new cluster.*/
01689             /* An act of minor evil - we use byteswritten as a scratch integer, knowing*/
01690             /* that its value is not used after updating *successcount above*/
01691             byteswritten = 0;
01692 
01693             lastcluster = fileinfo->cluster;
01694             fileinfo->cluster = DFS_GetFAT( fileinfo->volinfo, scratch, &byteswritten, fileinfo->cluster );
01695 
01696             /* Allocate a new cluster?*/
01697             if ( ( ( fileinfo->volinfo->filesystem == FAT12 ) && ( fileinfo->cluster >= 0xff8 ) ) ||
01698                     ( ( fileinfo->volinfo->filesystem == FAT16 ) && ( fileinfo->cluster >= 0xfff8 ) ) ||
01699                     ( ( fileinfo->volinfo->filesystem == FAT32 ) && ( fileinfo->cluster >= 0x0ffffff8 ) ) )
01700             {
01701                 uint32_t tempclus;
01702 
01703                 tempclus = DFS_GetFreeFAT( fileinfo->volinfo, scratch );
01704                 byteswritten = 0; /* invalidate cache*/
01705                 if ( tempclus == 0x0ffffff7 )
01706                     return DFS_ERRMISC;
01707 
01708                 /* Link new cluster onto file*/
01709                 DFS_SetFAT( fileinfo->volinfo, scratch, &byteswritten, lastcluster, tempclus );
01710                 fileinfo->cluster = tempclus;
01711 
01712                 /* Mark newly allocated cluster as end of chain         */
01713                 switch ( fileinfo->volinfo->filesystem )
01714                 {
01715                 case FAT12:     tempclus = 0xff8;   break;
01716                 case FAT16:     tempclus = 0xfff8;  break;
01717                 case FAT32:     tempclus = 0x0ffffff8;  break;
01718                 default:        return DFS_ERRMISC;
01719                 }
01720                 DFS_SetFAT( fileinfo->volinfo, scratch, &byteswritten, fileinfo->cluster, tempclus );
01721 
01722                 result = DFS_OK;
01723             }
01724             /* No else clause is required.*/
01725         }
01726     }
01727 
01728     /* Update directory entry*/
01729     if ( DFS_ReadSector( fileinfo->volinfo->unit, scratch, fileinfo->dirsector, 1 ) )
01730         return DFS_ERRMISC;
01731     ( ( PDIRENT ) scratch )[fileinfo->diroffset].filesize_0 = fileinfo->filelen & 0xff;
01732     ( ( PDIRENT ) scratch )[fileinfo->diroffset].filesize_1 = ( fileinfo->filelen & 0xff00 ) >> 8;
01733     ( ( PDIRENT ) scratch )[fileinfo->diroffset].filesize_2 = ( fileinfo->filelen & 0xff0000 ) >> 16;
01734     ( ( PDIRENT ) scratch )[fileinfo->diroffset].filesize_3 = ( fileinfo->filelen & 0xff000000 ) >> 24;
01735     if ( DFS_WriteSector( fileinfo->volinfo->unit, scratch, fileinfo->dirsector, 1 ) )
01736         return DFS_ERRMISC;
01737     return result;
01738 }
01739 
01740 NODEBUG u32 DFS_UnMount( enum STORAGE_device device )
01741 {
01742 #if SDCARD_SDIO
01743     SDIO_SetPowerState( SDIO_PowerState_OFF );
01744 #endif
01745     SD_DeInit();
01746 }
01747 
01748 NODEBUG u32 DFS_Mount( enum STORAGE_device device )
01749 {
01750     uint8_t sector[SECTOR_SIZE];
01751     uint32_t pstart, psize;
01752     uint8_t pactive, ptype;
01753 
01754     switch ( device )
01755     {
01756     case MMCSD_SDIO:
01757     {
01758         /*///////////////////////////////////////////////////////////////////*/
01759         /*////// SDCARD Initialisation //////////////////////////////////////*/
01760         /*///////////////Section adapted from ST example/////////////////////*/
01761 
01762         /*-------------------------- SD Init ----------------------------- */
01763         Status = SD_Init();
01764 
01765         if ( Status != SD_OK )
01766             return -1;
01767 
01768         if ( DFS_ReadSector( 0, sector, 0, 1 ) )
01769         {
01770             /*  Cannot read media!*/
01771             return -1;
01772         }
01773 
01774         if ( ( sector[0x1FE] == 0x55 ) & ( sector[0x1FF] == 0xAA ) )
01775         {
01776             /* The end of the last read sector contains a FAT or MBR end delimiter*/
01777             if ( ( sector[0x36] == 'F' ) & ( sector[0x37] == 'A' ) & ( sector[0x38] == 'T' ) )
01778             {
01779                 /* Well, this is not a MBR, but a FAT12/16 header!*/
01780                 pstart = 0;
01781                 pactive = 0x80;
01782                 ptype = 0x06;
01783                 psize = 0xFFFFFFFF;
01784             }
01785             else if ( ( sector[0x52] == 'F' ) & ( sector[0x53] == 'A' ) & ( sector[0x54] == 'T' ) )
01786             {
01787                 /*  Well, this is not a MBR, but a FAT32 header!*/
01788                 pstart = 0;
01789                 pactive = 0x80;
01790                 ptype = 0x06;
01791                 psize = 0xFFFFFFFF;
01792             }
01793             else
01794             {
01795                 pstart = DFS_GetPtnStart( 0, sector, 0, &pactive, &ptype, &psize );
01796                 if ( pstart == 0xffffffff )
01797                 {
01798                     /*  Cannot find first partition*/
01799                     return -1;
01800                 }
01801             }
01802             return pstart; /* starting sector of MBR of current partition*/
01803         }
01804     }
01805     default:
01806         break;
01807     }
01808 }