Newer
Older
/****************************************************************************
* Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved.
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
*
* References:
* Microsoft FAT documentation
* Some good ideas were leveraged from the FAT implementation:
* 'Copyright (C) 2007, ChaN, all right reserved.'
* which has an unrestricted license.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <stdbool.h>
#include <semaphore.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include <nuttx/fs.h>
#include <nuttx/fat.h>
#include "fs_internal.h"
#include "fs_fat32.h"
/****************************************************************************
* Definitions
****************************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/****************************************************************************
* Private Variables
****************************************************************************/
/****************************************************************************
* Public Variables
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: fat_checkfsinfo
*
* Desciption: Read the FAT32 FSINFO sector
*
****************************************************************************/
static int fat_checkfsinfo(struct fat_mountpt_s *fs)
{
/* Verify that this is, indeed, an FSINFO sector */
if (FSI_GETLEADSIG(fs->fs_buffer) == 0x41615252 &&
FSI_GETSTRUCTSIG(fs->fs_buffer) == 0x61417272 &&
FSI_GETTRAILSIG(fs->fs_buffer) == BOOT_SIGNATURE32)
{
fs->fs_fsinextfree = FSI_GETFREECOUNT(fs->fs_buffer);
fs->fs_fsifreecount = FSI_GETNXTFREE(fs->fs_buffer);
return OK;
}
}
return -ENODEV;
}
/****************************************************************************
* Name: fat_checkbootrecord
*
* Desciption: Read a sector and verify that it is a a FAT boot record.
*
****************************************************************************/
static int fat_checkbootrecord(struct fat_mountpt_s *fs)
{
uint32_t ndatasectors;
uint32_t ntotalfatsects;
uint16_t rootdirsectors = 0;
bool notfat32 = false;
/* Verify the MBR signature at offset 510 in the sector (true even
* if the sector size is greater than 512. All FAT file systems have
* this signature. On a FAT32 volume, the RootEntCount , FatSz16, and
* FatSz32 values should always be zero. The FAT sector size should
* match the reported hardware sector size.
*/
if (MBR_GETSIGNATURE(fs->fs_buffer) != BOOT_SIGNATURE16 ||
MBR_GETBYTESPERSEC(fs->fs_buffer) != fs->fs_hwsectorsize)
{
fdbg("ERROR: Signature: %04x FS sectorsize: %d HW sectorsize: %d\n",
MBR_GETSIGNATURE(fs->fs_buffer), MBR_GETBYTESPERSEC(fs->fs_buffer),
fs->fs_hwsectorsize);
return -ENODEV;
}
/* Verify the FAT32 file system type. The determination of the file
* system type is based on the number of clusters on the volume: FAT12
* volume has <= FAT_MAXCLUST12 (4084) clusters, a FAT16 volume has <=
* FAT_MINCLUST16 (microsfoft says < 65,525) clusters, and any larger
* is FAT32.
*
* Get the number of 32-bit directory entries in root directory (zero
*/
fs->fs_rootentcnt = MBR_GETROOTENTCNT(fs->fs_buffer);
if (fs->fs_rootentcnt != 0)
notfat32 = true; /* Must be zero for FAT32 */
rootdirsectors = (32 * fs->fs_rootentcnt + fs->fs_hwsectorsize - 1) / fs->fs_hwsectorsize;
fs->fs_nfatsects = MBR_GETFATSZ16(fs->fs_buffer); /* Should be zero */
if (fs->fs_nfatsects)
notfat32 = true; /* Must be zero for FAT32 */
fs->fs_nfatsects = MBR_GETFATSZ32(fs->fs_buffer);
if (!fs->fs_nfatsects || fs->fs_nfatsects >= fs->fs_hwnsectors)
fdbg("ERROR: fs_nfatsects %d fs_hwnsectors: %d\n",
fs->fs_nfatsects, fs->fs_hwnsectors);
return -ENODEV;
}
/* Get the total number of sectors on the volume. */
fs->fs_fattotsec = MBR_GETTOTSEC16(fs->fs_buffer); /* Should be zero */
if (fs->fs_fattotsec)
{
notfat32 = true; /* Must be zero for FAT32 */
}
else
{
fs->fs_fattotsec = MBR_GETTOTSEC32(fs->fs_buffer);
}
if (!fs->fs_fattotsec || fs->fs_fattotsec > fs->fs_hwnsectors)
{
fdbg("ERROR: fs_fattotsec %d fs_hwnsectors: %d\n",
fs->fs_fattotsec, fs->fs_hwnsectors);
return -ENODEV;
}
/* Get the total number of reserved sectors */
fs->fs_fatresvdseccount = MBR_GETRESVDSECCOUNT(fs->fs_buffer);
if (fs->fs_fatresvdseccount > fs->fs_hwnsectors)
{
fdbg("ERROR: fs_fatresvdseccount %d fs_hwnsectors: %d\n",
fs->fs_fatresvdseccount, fs->fs_hwnsectors);
return -ENODEV;
}
/* Get the number of FATs. This is probably two but could have other values */
fs->fs_fatnumfats = MBR_GETNUMFATS(fs->fs_buffer);
ntotalfatsects = fs->fs_fatnumfats * fs->fs_nfatsects;
ndatasectors = fs->fs_fattotsec - fs->fs_fatresvdseccount - ntotalfatsects - rootdirsectors;
fdbg("ERROR: ndatasectors %d fs_hwnsectors: %d\n",
ndatasectors, fs->fs_hwnsectors);
return -ENODEV;
}
/* Get the sectors per cluster */
fs->fs_fatsecperclus = MBR_GETSECPERCLUS(fs->fs_buffer);
/* Calculate the number of clusters */
fs->fs_nclusters = ndatasectors / fs->fs_fatsecperclus;
/* Finally, the test: */
{
fs->fs_fsinfo = 0;
fs->fs_type = FSTYPE_FAT12;
}
{
fs->fs_fsinfo = 0;
fs->fs_type = FSTYPE_FAT16;
}
else if (!notfat32)
{
fs->fs_fsinfo = fs->fs_fatbase + MBR_GETFSINFO(fs->fs_buffer);
fs->fs_type = FSTYPE_FAT32;
fdbg("ERROR: notfat32: %d fs_nclusters: %d\n",
notfat32, fs->fs_nclusters);
return -ENODEV;
}
/* We have what appears to be a valid FAT filesystem! Save a few more things
* from the boot record that we will need later.
*/
fs->fs_fatbase += fs->fs_fatresvdseccount;
if (fs->fs_type == FSTYPE_FAT32)
{
fs->fs_rootbase = MBR_GETROOTCLUS(fs->fs_buffer);
}
else
{
fs->fs_rootbase = fs->fs_fatbase + ntotalfatsects;
fs->fs_database = fs->fs_fatbase + ntotalfatsects + fs->fs_rootentcnt / DIRSEC_NDIRS(fs);
fs->fs_fsifreecount = 0xffffffff;
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: fat_getuint16
****************************************************************************/
uint16_t fat_getuint16(uint8_t *ptr)
{
#ifdef CONFIG_ENDIAN_BIG
/* The bytes always have to be swapped if the target is big-endian */
return ((uint16_t)ptr[0] << 8) | ptr[1];
#else
/* Byte-by-byte transfer is still necessary if the address is un-aligned */
return ((uint16_t)ptr[1] << 8) | ptr[0];
#endif
}
/****************************************************************************
* Name: fat_getuint32
****************************************************************************/
uint32_t fat_getuint32(uint8_t *ptr)
{
#ifdef CONFIG_ENDIAN_BIG
/* The bytes always have to be swapped if the target is big-endian */
return ((uint32_t)fat_getuint16(&ptr[0]) << 16) | fat_getuint16(&ptr[2]);
#else
/* Byte-by-byte transfer is still necessary if the address is un-aligned */
return ((uint32_t)fat_getuint16(&ptr[2]) << 16) | fat_getuint16(&ptr[0]);
#endif
}
/****************************************************************************
* Name: fat_putuint16
****************************************************************************/
void fat_putuint16(uint8_t *ptr, uint16_t value16)
#ifdef CONFIG_ENDIAN_BIG
/* The bytes always have to be swapped if the target is big-endian */
ptr[0] = val[1];
ptr[1] = val[0];
#else
/* Byte-by-byte transfer is still necessary if the address is un-aligned */
ptr[0] = val[0];
ptr[1] = val[1];
#endif
}
/****************************************************************************
* Name: fat_putuint32
****************************************************************************/
void fat_putuint32(uint8_t *ptr, uint32_t value32)
uint16_t *val = (uint16_t*)&value32;
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
#ifdef CONFIG_ENDIAN_BIG
/* The bytes always have to be swapped if the target is big-endian */
fat_putuint16(&ptr[0], val[2]);
fat_putuint16(&ptr[2], val[0]);
#else
/* Byte-by-byte transfer is still necessary if the address is un-aligned */
fat_putuint16(&ptr[0], val[0]);
fat_putuint16(&ptr[2], val[2]);
#endif
}
/****************************************************************************
* Name: fat_semtake
****************************************************************************/
void fat_semtake(struct fat_mountpt_s *fs)
{
/* Take the semaphore (perhaps waiting) */
while (sem_wait(&fs->fs_sem) != 0)
{
/* The only case that an error should occur here is if
* the wait was awakened by a signal.
*/
ASSERT(*get_errno_ptr() == EINTR);
}
}
/****************************************************************************
* Name: fat_semgive
****************************************************************************/
void fat_semgive(struct fat_mountpt_s *fs)
{
sem_post(&fs->fs_sem);
}
/****************************************************************************
* Name: fat_systime2fattime
*
* Desciption: Get the system time convert to a time and and date suitble
* for writing into the FAT FS.
*
* TIME in LS 16-bits:
* Bits 0:4 = 2 second count (0-29 representing 0-58 seconds)
* Bits 5-10 = minutes (0-59)
* Bits 11-15 = hours (0-23)
* DATE in MS 16-bits
* Bits 5:8 = Month of year (1-12)
* Bits 9:15 = Year from 1980 (0-127 representing 1980-2107)
*
****************************************************************************/
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
/* Unless you have a hardware RTC or some other to get accurate time, then
* there is no reason to support FAT time.
*/
#ifdef CONFIG_FS_FATTIME
struct timespec ts;
struct tm tm;
int ret;
/* Get the current time in seconds and nanoseconds */
ret = clock_settime(CLOCK_REALTIME, &ts);
if (ret == OK)
{
/* Break done the seconds in date and time units */
if (gmtime_r((FAR const time_t *)&ts.tv_sec, &tm) != NULL)
{
/* FAT can only represent dates since 1980. struct tm can
* represent dates since 1900.
*/
if (tm.tm_year >= 80)
{
uint16_t fattime;
uint16_t fatdate;
fattime = (tm.tm_sec >> 1) & 0x001f; /* Bits 0-4: 2 second count (0-29) */
fattime |= (tm.tm_min << 5) & 0x07e0; /* Bits 5-10: minutes (0-59) */
fattime |= (tm.tm_hour << 11) & 0xf800; /* Bits 11-15: hours (0-23) */
fatdate = tm.tm_mday & 0x001f; /* Bits 0-4: Day of month (1-31) */
fatdate |= ((tm.tm_mon+1) << 5) & 0x01e0; /* Bits 5-8: Month of year (1-12) */
fatdate |= ((tm.tm_year-80) << 9) & 0xfe00; /* Bits 9-15: Year from 1980 */
return (uint32_t)fatdate << 16 | (uint32_t)fattime;
}
}
}
#endif
return 0;
}
/****************************************************************************
* Name: fat_fattime2systime
*
* Desciption: Convert FAT data and time to a system time_t
*
* 16-bit FAT time:
* Bits 0:4 = 2 second count (0-29 representing 0-58 seconds)
* Bits 5-10 = minutes (0-59)
* Bits 11-15 = hours (0-23)
* 16-bit FAT date:
* Bits 5:8 = Month of year (1-12)
* Bits 9:15 = Year from 1980 (0-127 representing 1980-2107)
*
****************************************************************************/
time_t fat_fattime2systime(uint16_t fattime, uint16_t fatdate)
/* Unless you have a hardware RTC or some other to get accurate time, then
* there is no reason to support FAT time.
*/
#ifdef CONFIG_FS_FATTIME
struct tm tm;
unsigned int tmp;
/* Break out the date and time */
tm.tm_sec = (fatdate & 0x001f) << 1; /* Bits 0-4: 2 second count (0-29) */
tm.tm_min = (fatdate & 0x07e0) >> 5; /* Bits 5-10: minutes (0-59) */
tm.tm_hour = (fatdate & 0xf800) >> 11; /* Bits 11-15: hours (0-23) */
tm.tm_mday = (fatdate & 0x001f); /* Bits 0-4: Day of month (1-31) */
tmp = ((fatdate & 0x01e0) >> 5); /* Bits 5-8: Month of year (1-12) */
tm.tm_mon = tmp > 0 ? tmp-1 : 0;
tm.tm_year = ((fatdate & 0xfe00) >> 9) + 80; /* Bits 9-15: Year from 1980 */
/* Then convert the broken out time into seconds since the epoch */
return mktime(&tm);
#else
}
/****************************************************************************
* Name: fat_mount
*
* Desciption: This function is called only when the mountpoint is first
* established. It initializes the mountpoint structure and verifies
* that a valid FAT32 filesystem is provided by the block driver.
*
* The caller should hold the mountpoint semaphore
*
****************************************************************************/
int fat_mount(struct fat_mountpt_s *fs, bool writeable)
{
FAR struct inode *inode;
struct geometry geo;
int ret;
/* Assume that the mount is successful */
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
/* Check if there is media available */
inode = fs->fs_blkdriver;
if (!inode || !inode->u.i_bops || !inode->u.i_bops->geometry ||
inode->u.i_bops->geometry(inode, &geo) != OK || !geo.geo_available)
{
ret = -ENODEV;
goto errout;
}
/* Make sure that that the media is write-able (if write access is needed) */
if (writeable && !geo.geo_writeenabled)
{
ret = -EACCES;
goto errout;
}
/* Save the hardware geometry */
fs->fs_hwsectorsize = geo.geo_sectorsize;
fs->fs_hwnsectors = geo.geo_nsectors;
/* Allocate a buffer to hold one hardware sector */
fs->fs_buffer = (uint8_t*)kmalloc(fs->fs_hwsectorsize);
if (!fs->fs_buffer)
{
ret = -ENOMEM;
goto errout;
}
/* Search FAT boot record on the drive. First check at sector zero. This
* could be either the boot record or a partition that refers to the boot
* record.
*
* First read sector zero. This will be the first access to the drive and a
* likely failure point.
*/
fs->fs_fatbase = 0;
ret = fat_hwread(fs, fs->fs_buffer, 0, 1);
if (ret < 0)
{
goto errout_with_buffer;
}
ret = fat_checkbootrecord(fs);
if (ret != OK)
{
/* The contents of sector 0 is not a boot record. It could be a
* partition, however. Assume it is a partition and get the offset
* into the partition table. This table is at offset MBR_TABLE and is
* indexed by 16x the partition number.
int i;
for (i = 0; i < 4; i++)
{
/* Check if the partition exists and, if so, get the bootsector for that
* partition and see if we can find the boot record there.
*/
uint8_t part = PART_GETTYPE(i, fs->fs_buffer);
fvdbg("Partition %d, offset %d, type %d\n", i, PART_ENTRY(i), part);
if (part == 0)
{
fvdbg("No partition %d\n", i);
continue;
}
/* There appears to be a partition, get the sector number of the
* partition (LBA)
*/
fs->fs_fatbase = PART_GETSTARTSECTOR(i, fs->fs_buffer);
/* Read the new candidate boot sector */
ret = fat_hwread(fs, fs->fs_buffer, fs->fs_fatbase, 1);
if (ret < 0)
{
/* Failed to read the sector */
goto errout_with_buffer;
}
/* Check if this is a boot record */
ret = fat_checkbootrecord(fs);
if (ret == OK)
{
/* Break out of the loop if a valid boot record is found */
fvdbg("MBR found in partition %d\n", i);
break;
}
/* Re-read sector 0 so that we can check the next partition */
fvdbg("Partition %d is not an MBR\n", i);
ret = fat_hwread(fs, fs->fs_buffer, 0, 1);
if (ret < 0)
{
goto errout_with_buffer;
}
}
if (i > 3)
{
fdbg("No valid MBR\n");
goto errout_with_buffer;
}
}
/* We have what appears to be a valid FAT filesystem! Now read the
* FSINFO sector (FAT32 only)
*/
if (fs->fs_type == FSTYPE_FAT32)
{
ret = fat_checkfsinfo(fs);
if (ret != OK)
{
}
}
/* We did it! */
fdbg("FAT%d:\n", fs->fs_type == 0 ? 12 : fs->fs_type == 1 ? 16 : 32);
fdbg("\tHW sector size: %d\n", fs->fs_hwsectorsize);
fdbg("\t sectors: %d\n", fs->fs_hwnsectors);
fdbg("\tFAT reserved: %d\n", fs->fs_fatresvdseccount);
fdbg("\t sectors: %d\n", fs->fs_fattotsec);
fdbg("\t start sector: %d\n", fs->fs_fatbase);
fdbg("\t root sector: %d\n", fs->fs_rootbase);
fdbg("\t root entries: %d\n", fs->fs_rootentcnt);
fdbg("\t data sector: %d\n", fs->fs_database);
fdbg("\t FSINFO sector: %d\n", fs->fs_fsinfo);
fdbg("\t Num FATs: %d\n", fs->fs_fatnumfats);
fdbg("\t FAT sectors: %d\n", fs->fs_nfatsects);
fdbg("\t sectors/cluster: %d\n", fs->fs_fatsecperclus);
fdbg("\t max clusters: %d\n", fs->fs_nclusters);
fdbg("\tFSI free count %d\n", fs->fs_fsifreecount);
fdbg("\t next free %d\n", fs->fs_fsinextfree);
return OK;
errout_with_buffer:
return ret;
}
/****************************************************************************
* Name: fat_checkmount
*
* Desciption: Check if the mountpoint is still valid.
*
* The caller should hold the mountpoint semaphore
*
****************************************************************************/
int fat_checkmount(struct fat_mountpt_s *fs)
{
/* If the fs_mounted flag is false, then we have already handled the loss
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
* of the mount.
*/
if (fs && fs->fs_mounted)
{
struct fat_file_s *file;
/* We still think the mount is healthy. Check an see if this is
* still the case
*/
if (fs->fs_blkdriver)
{
struct inode *inode = fs->fs_blkdriver;
if (inode && inode->u.i_bops && inode->u.i_bops->geometry)
{
struct geometry geo;
int errcode = inode->u.i_bops->geometry(inode, &geo);
if (errcode == OK && geo.geo_available && !geo.geo_mediachanged)
{
return OK;
}
}
}
/* If we get here, the mount is NOT healthy */
/* Make sure that this is flagged in every opened file */
for (file = fs->fs_head; file; file = file->ff_next)
{
}
}
return -ENODEV;
}
/****************************************************************************
* Name: fat_hwread
*
* Desciption: Read the specified sector into the sector buffer
*
****************************************************************************/
int fat_hwread(struct fat_mountpt_s *fs, uint8_t *buffer, off_t sector,
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
unsigned int nsectors)
{
int ret = -ENODEV;
if (fs && fs->fs_blkdriver )
{
struct inode *inode = fs->fs_blkdriver;
if (inode && inode->u.i_bops && inode->u.i_bops->read)
{
ssize_t nSectorsRead = inode->u.i_bops->read(inode, buffer,
sector, nsectors);
if (nSectorsRead == nsectors)
{
ret = OK;
}
else if (nSectorsRead < 0)
{
ret = nSectorsRead;
}
}
}
return ret;
}
/****************************************************************************
* Name: fat_hwwrite
*
* Desciption: Write the sector buffer to the specified sector
*
****************************************************************************/
int fat_hwwrite(struct fat_mountpt_s *fs, uint8_t *buffer, off_t sector,
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
unsigned int nsectors)
{
int ret = -ENODEV;
if (fs && fs->fs_blkdriver )
{
struct inode *inode = fs->fs_blkdriver;
if (inode && inode->u.i_bops && inode->u.i_bops->write)
{
ssize_t nSectorsWritten =
inode->u.i_bops->write(inode, buffer, sector, nsectors);
if (nSectorsWritten == nsectors)
{
ret = OK;
}
else if (nSectorsWritten < 0)
{
ret = nSectorsWritten;
}
}
}
return ret;
}
/****************************************************************************
* Name: fat_cluster2sector
*
* Desciption: Convert a cluster number to a start sector number
*
****************************************************************************/
off_t fat_cluster2sector(struct fat_mountpt_s *fs, uint32_t cluster )
{
cluster -= 2;
if (cluster >= fs->fs_nclusters - 2)
{
return -EINVAL;
}
return cluster * fs->fs_fatsecperclus + fs->fs_database;
}
/****************************************************************************
* Name: fat_getcluster
*
*
* Return: <0: error, 0:cluster unassigned, >=0: start sector of cluster
*
****************************************************************************/
off_t fat_getcluster(struct fat_mountpt_s *fs, uint32_t clusterno)
{
/* Verify that the cluster number is within range */
if (clusterno >= 2 && clusterno < fs->fs_nclusters)
{
/* Okay.. Read the next cluster from the FAT. The way we will do
* this depends on the type of FAT filesystm we are dealing with.
*/
switch (fs->fs_type)
{
case FSTYPE_FAT12 :
{
off_t fatsector;
unsigned int fatindex;
/* FAT12 is more complex because it has 12-bits (1.5 bytes)
* per FAT entry. Get the offset to the first byte:
*/
fatoffset = (clusterno * 3) / 2;
fatsector = fs->fs_fatbase + SEC_NSECTORS(fs, fatoffset);
/* Read the sector at this offset */
if (fat_fscacheread(fs, fatsector) < 0)
{
/* Read error */
break;
}
/* Get the first, LS byte of the cluster from the FAT */
fatindex = fatoffset & SEC_NDXMASK(fs);
cluster = fs->fs_buffer[fatindex];
/* With FAT12, the second byte of the cluster number may lie in
* a different sector than the first byte.
*/
fatindex++;
if (fatindex >= fs->fs_hwsectorsize)
{
fatsector++;
fatindex = 0;
if (fat_fscacheread(fs, fatsector) < 0)
{
/* Read error */
break;
}
}
/* Get the second, MS byte of the cluster for 16-bits. The
* does not depend on the endian-ness of the target, but only
* on the fact that the byte stream is little-endian.
*/
/* Now, pick out the correct 12 bit cluster start sector value */
if ((clusterno & 1) != 0)
{
/* Odd.. take the MS 12-bits */
}
case FSTYPE_FAT16 :
{
unsigned int fatoffset = 2 * clusterno;
off_t fatsector = fs->fs_fatbase + SEC_NSECTORS(fs, fatoffset);
unsigned int fatindex = fatoffset & SEC_NDXMASK(fs);
if (fat_fscacheread(fs, fatsector) < 0)
{
/* Read error */
break;
}
return FAT_GETFAT16(fs->fs_buffer, fatindex);
}
case FSTYPE_FAT32 :
{
unsigned int fatoffset = 4 * clusterno;
off_t fatsector = fs->fs_fatbase + SEC_NSECTORS(fs, fatoffset);
unsigned int fatindex = fatoffset & SEC_NDXMASK(fs);
if (fat_fscacheread(fs, fatsector) < 0)
{
/* Read error */
break;
}
}
default:
break;
}
}
/* There is no cluster information, or an error occured */
return (off_t)-EINVAL;
}
/****************************************************************************
* Name: fat_putcluster
*
*
****************************************************************************/
int fat_putcluster(struct fat_mountpt_s *fs, uint32_t clusterno, off_t nextcluster)
{
/* Verify that the cluster number is within range. Zero erases the cluster. */
if (clusterno == 0 || (clusterno >= 2 && clusterno < fs->fs_nclusters))
{
/* Okay.. Write the next cluster into the FAT. The way we will do
* this depends on the type of FAT filesystm we are dealing with.
*/
switch (fs->fs_type)
{
case FSTYPE_FAT12 :
{
off_t fatsector;
/* FAT12 is more complex because it has 12-bits (1.5 bytes)
* per FAT entry. Get the offset to the first byte:
*/
fatoffset = (clusterno * 3) / 2;
fatsector = fs->fs_fatbase + SEC_NSECTORS(fs, fatoffset);
/* Make sure that the sector at this offset is in the cache */
if (fat_fscacheread(fs, fatsector)< 0)
{
/* Read error */
/* Get the LS byte first handling the 12-bit alignment within
* the 16-bits
*/
fatindex = fatoffset & SEC_NDXMASK(fs);
if ((clusterno & 1) != 0)
{
/* Save the LS four bits of the next cluster */
value = (fs->fs_buffer[fatindex] & 0x0f) | nextcluster << 4;
/* Save the LS eight bits of the next cluster */