FAT fixes for extending directory entries with long file names. From RonenV
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5802 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
49de19ed4b
commit
bc247a45a0
@ -4472,4 +4472,9 @@
|
||||
implementation of the LPC17 DMA and integration into the SDCARD
|
||||
driver (2013-3-29).
|
||||
* arch/arm/src/lpc17xx/lpc17_gdma.c: LPC17 DMA is code complete and
|
||||
under test. Does not yet work (2013-3-30).
|
||||
under test. Does not yet work (2013-3-30).
|
||||
* fs/fat/fs_fat32dirent.c and fs_fat32util.c: Several fixes to the
|
||||
FAT file system from Ronen Vainish. These fixes mostly involve the
|
||||
logic to extend directory clusters for the case of long file names
|
||||
but also include a few important general fixes (such as for storing
|
||||
32 bit FAT values) (2013-03-31).
|
||||
|
@ -2466,7 +2466,7 @@ static int lpc17_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
|
||||
|
||||
lpc17_configxfrints(priv, SDCARD_DMARECV_MASK);
|
||||
|
||||
regval = getreg32(LPC17_SDCARD_DCTRL);
|
||||
regval = getreg32(LPC17_SDCARD_DCTRL);
|
||||
regval |= SDCARD_DCTRL_DMAEN;
|
||||
putreg32(regval, LPC17_SDCARD_DCTRL);
|
||||
|
||||
@ -2549,7 +2549,7 @@ static int lpc17_dmasendsetup(FAR struct sdio_dev_s *dev,
|
||||
{
|
||||
lpc17_sample(priv, SAMPLENDX_BEFORE_ENABLE);
|
||||
|
||||
regval = getreg32(LPC17_SDCARD_DCTRL);
|
||||
regval = getreg32(LPC17_SDCARD_DCTRL);
|
||||
regval |= SDCARD_DCTRL_DMAEN;
|
||||
putreg32(regval, LPC17_SDCARD_DCTRL);
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
* fs/fat/fs_fat32dirent.c
|
||||
*
|
||||
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2011, 2013 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -264,7 +264,7 @@ static inline int fat_parsesfname(const char **path,
|
||||
/* Initialized the name with all spaces */
|
||||
|
||||
memset(dirinfo->fd_name, ' ', DIR_MAXFNAME);
|
||||
|
||||
|
||||
/* Loop until the name is successfully parsed or an error occurs */
|
||||
|
||||
endndx = 8;
|
||||
@ -626,7 +626,7 @@ static inline int fat_createalias(struct fat_dirinfo_s *dirinfo)
|
||||
/* Initialized the short name with all spaces */
|
||||
|
||||
memset(dirinfo->fd_name, ' ', DIR_MAXFNAME);
|
||||
|
||||
|
||||
/* Handle a special case where there is no name. Windows seems to use
|
||||
* the extension plus random stuff then ~1 to pat to 8 bytes. Some
|
||||
* examples:
|
||||
@ -705,7 +705,7 @@ static inline int fat_createalias(struct fat_dirinfo_s *dirinfo)
|
||||
/* Handle lower case characters */
|
||||
|
||||
ch = toupper(ch);
|
||||
|
||||
|
||||
/* We now have a valid character to add to the name or extension. */
|
||||
|
||||
dirinfo->fd_name[ndx++] = ch;
|
||||
@ -1363,7 +1363,7 @@ static inline int fat_findlfnentry(struct fat_mountpt_s *fs,
|
||||
}
|
||||
|
||||
/* Continue at the next directory entry */
|
||||
|
||||
|
||||
next_entry:
|
||||
if (fat_nextdirentry(fs, &dirinfo->dir) != OK)
|
||||
{
|
||||
@ -1553,7 +1553,7 @@ static inline int fat_allocatelfnentry(struct fat_mountpt_s *fs,
|
||||
/* Is this last entry we need (i.e., the entry for the short
|
||||
* file name entry)?
|
||||
*/
|
||||
|
||||
|
||||
if (needed <= 1)
|
||||
{
|
||||
/* Yes.. remember the position of this entry and return
|
||||
@ -1920,7 +1920,7 @@ static inline int fat_getlfname(struct fat_mountpt_s *fs, struct fs_dirent_s *di
|
||||
static int fat_putsfname(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo)
|
||||
{
|
||||
uint8_t *direntry = &fs->fs_buffer[dirinfo->fd_seq.ds_offset];
|
||||
|
||||
|
||||
/* Write the short directory entry */
|
||||
|
||||
memcpy(&direntry[DIR_NAME], dirinfo->fd_name, DIR_MAXFNAME);
|
||||
@ -2011,6 +2011,7 @@ static int fat_putlfname(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo
|
||||
uint8_t offset;
|
||||
uint8_t seqno;
|
||||
uint8_t checksum;
|
||||
off_t startsector;
|
||||
int namelen;
|
||||
int ret;
|
||||
|
||||
@ -2051,6 +2052,13 @@ static int fat_putlfname(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo
|
||||
dirinfo->dir.fd_currsector = dirinfo->fd_seq.ds_lfnsector;
|
||||
dirinfo->dir.fd_index = dirinfo->fd_seq.ds_lfnoffset / DIR_SIZE;
|
||||
|
||||
/* ds_lfnoffset is the offset in the sector. However fd_index is used as
|
||||
* index for the entire cluster. We need to add that offset
|
||||
*/
|
||||
|
||||
startsector = fat_cluster2sector(fs, dirinfo->dir.fd_currcluster);
|
||||
dirinfo->dir.fd_index += (dirinfo->dir.fd_currsector - startsector) * DIRSEC_NDIRS(fs);
|
||||
|
||||
/* Make sure that the alias is unique in this directory*/
|
||||
|
||||
ret = fat_uniquealias(fs, dirinfo);
|
||||
@ -2070,7 +2078,7 @@ static int fat_putlfname(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo
|
||||
/* Make sure that the sector containing the "last" long file name entry
|
||||
* is in the sector cache (it probably is not).
|
||||
*/
|
||||
|
||||
|
||||
ret = fat_fscacheread(fs, dirinfo->dir.fd_currsector);
|
||||
if (ret < 0)
|
||||
{
|
||||
@ -2126,7 +2134,7 @@ static int fat_putlfname(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo
|
||||
}
|
||||
|
||||
/* The remainder should now be zero */
|
||||
|
||||
|
||||
DEBUGASSERT(remainder == 0);
|
||||
}
|
||||
else
|
||||
@ -2328,7 +2336,7 @@ int fat_finddirentry(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo,
|
||||
* the sector containing the short file name directory entry
|
||||
* in the cache.
|
||||
*/
|
||||
|
||||
|
||||
ret = fat_findlfnentry(fs, dirinfo);
|
||||
}
|
||||
else
|
||||
@ -2405,13 +2413,15 @@ int fat_finddirentry(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo,
|
||||
/****************************************************************************
|
||||
* Name: fat_allocatedirentry
|
||||
*
|
||||
* Desciption: Find a free directory entry
|
||||
* Desciption:
|
||||
* Find (or allocate) all needed directory entries to contain the file name
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int fat_allocatedirentry(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo)
|
||||
{
|
||||
int32_t cluster;
|
||||
int32_t prevcluster;
|
||||
off_t sector;
|
||||
int ret;
|
||||
int i;
|
||||
@ -2445,7 +2455,7 @@ int fat_allocatedirentry(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo
|
||||
/* Start at the first entry in the root directory. */
|
||||
|
||||
dirinfo->dir.fd_index = 0;
|
||||
|
||||
|
||||
/* Is this a path segment a long or a short file. Was a long file
|
||||
* name parsed?
|
||||
*/
|
||||
@ -2456,7 +2466,7 @@ int fat_allocatedirentry(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo
|
||||
/* Yes.. Allocate for the sequence of long file name directory
|
||||
* entries plus a short file name directory entry.
|
||||
*/
|
||||
|
||||
|
||||
ret = fat_allocatelfnentry(fs, dirinfo);
|
||||
}
|
||||
|
||||
@ -2495,7 +2505,9 @@ int fat_allocatedirentry(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo
|
||||
|
||||
/* Try to extend the cluster chain for this directory */
|
||||
|
||||
cluster = fat_extendchain(fs, dirinfo->dir.fd_currcluster);
|
||||
prevcluster = cluster;
|
||||
cluster = fat_extendchain(fs, dirinfo->dir.fd_currcluster);
|
||||
|
||||
if (cluster < 0)
|
||||
{
|
||||
return cluster;
|
||||
@ -2524,8 +2536,13 @@ int fat_allocatedirentry(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
sector++;
|
||||
}
|
||||
|
||||
/* Start the search again */
|
||||
|
||||
cluster = prevcluster;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2545,6 +2562,7 @@ int fat_freedirentry(struct fat_mountpt_s *fs, struct fat_dirseq_s *seq)
|
||||
struct fs_fatdir_s dir;
|
||||
uint16_t diroffset;
|
||||
uint8_t *direntry;
|
||||
off_t startsector;
|
||||
int ret;
|
||||
|
||||
/* Set it to the cluster containing the "last" LFN entry (that appears
|
||||
@ -2555,6 +2573,13 @@ int fat_freedirentry(struct fat_mountpt_s *fs, struct fat_dirseq_s *seq)
|
||||
dir.fd_currsector = seq->ds_lfnsector;
|
||||
dir.fd_index = seq->ds_lfnoffset / DIR_SIZE;
|
||||
|
||||
/* Remember that ds_lfnoffset is the offset in the sector and not the
|
||||
* cluster.
|
||||
*/
|
||||
|
||||
startsector = fat_cluster2sector(fs, dir.fd_currcluster);
|
||||
dir.fd_index += (dir.fd_currsector - startsector) * DIRSEC_NDIRS(fs);
|
||||
|
||||
/* Free all of the directory entries used for the sequence of long file name
|
||||
* and for the single short file name entry.
|
||||
*/
|
||||
@ -2655,7 +2680,7 @@ int fat_dirname2path(struct fat_mountpt_s *fs, struct fs_dirent_s *dir)
|
||||
/* Yes.. Get the name from a sequence of long file name directory
|
||||
* entries.
|
||||
*/
|
||||
|
||||
|
||||
return fat_getlfname(fs, dir);
|
||||
}
|
||||
else
|
||||
@ -2691,7 +2716,7 @@ int fat_dirnamewrite(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo)
|
||||
/* Write the sequence of long file name directory entries (this function
|
||||
* also creates the short file name alias).
|
||||
*/
|
||||
|
||||
|
||||
ret = fat_putlfname(fs, dirinfo);
|
||||
if (ret != OK)
|
||||
{
|
||||
@ -2735,7 +2760,7 @@ int fat_dirwrite(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo,
|
||||
/* Write the sequence of long file name directory entries (this function
|
||||
* also creates the short file name alias).
|
||||
*/
|
||||
|
||||
|
||||
ret = fat_putlfname(fs, dirinfo);
|
||||
if (ret != OK)
|
||||
{
|
||||
|
@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
* fs/fat/fs_fat32util.c
|
||||
*
|
||||
* Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2007-2009, 2011, 2013 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* References:
|
||||
@ -275,7 +275,7 @@ static int fat_checkbootrecord(struct fat_mountpt_s *fs)
|
||||
}
|
||||
else
|
||||
{
|
||||
fs->fs_rootbase = fs->fs_fatbase + ntotalfatsects;
|
||||
fs->fs_rootbase = fs->fs_fatbase + ntotalfatsects;
|
||||
}
|
||||
|
||||
fs->fs_database = fs->fs_fatbase + ntotalfatsects + fs->fs_rootentcnt / DIRSEC_NDIRS(fs);
|
||||
@ -349,16 +349,17 @@ void fat_putuint16(uint8_t *ptr, uint16_t value16)
|
||||
void fat_putuint32(uint8_t *ptr, uint32_t value32)
|
||||
{
|
||||
uint16_t *val = (uint16_t*)&value32;
|
||||
|
||||
#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[0], val[1]);
|
||||
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]);
|
||||
fat_putuint16(&ptr[2], val[1]);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -579,7 +580,7 @@ int fat_mount(struct fat_mountpt_s *fs, bool writeable)
|
||||
/* 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);
|
||||
|
||||
@ -670,6 +671,7 @@ int fat_mount(struct fat_mountpt_s *fs, bool writeable)
|
||||
errout_with_buffer:
|
||||
fat_io_free(fs->fs_buffer, fs->fs_hwsectorsize);
|
||||
fs->fs_buffer = 0;
|
||||
|
||||
errout:
|
||||
fs->fs_mounted = false;
|
||||
return ret;
|
||||
@ -886,6 +888,7 @@ off_t fat_getcluster(struct fat_mountpt_s *fs, uint32_t clusterno)
|
||||
|
||||
cluster &= 0x0fff;
|
||||
}
|
||||
|
||||
return cluster;
|
||||
}
|
||||
|
||||
@ -898,8 +901,10 @@ off_t fat_getcluster(struct fat_mountpt_s *fs, uint32_t clusterno)
|
||||
if (fat_fscacheread(fs, fatsector) < 0)
|
||||
{
|
||||
/* Read error */
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return FAT_GETFAT16(fs->fs_buffer, fatindex);
|
||||
}
|
||||
|
||||
@ -912,10 +917,13 @@ off_t fat_getcluster(struct fat_mountpt_s *fs, uint32_t clusterno)
|
||||
if (fat_fscacheread(fs, fatsector) < 0)
|
||||
{
|
||||
/* Read error */
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return FAT_GETFAT32(fs->fs_buffer, fatindex) & 0x0fffffff;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1046,6 +1054,7 @@ int fat_putcluster(struct fat_mountpt_s *fs, uint32_t clusterno, off_t nextclust
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
FAT_PUTFAT16(fs->fs_buffer, fatindex, nextcluster & 0xffff);
|
||||
}
|
||||
break;
|
||||
@ -1055,6 +1064,7 @@ int fat_putcluster(struct fat_mountpt_s *fs, uint32_t clusterno, off_t nextclust
|
||||
unsigned int fatoffset = 4 * clusterno;
|
||||
off_t fatsector = fs->fs_fatbase + SEC_NSECTORS(fs, fatoffset);
|
||||
unsigned int fatindex = fatoffset & SEC_NDXMASK(fs);
|
||||
uint32_t val;
|
||||
|
||||
if (fat_fscacheread(fs, fatsector) < 0)
|
||||
{
|
||||
@ -1062,7 +1072,11 @@ int fat_putcluster(struct fat_mountpt_s *fs, uint32_t clusterno, off_t nextclust
|
||||
|
||||
break;
|
||||
}
|
||||
FAT_PUTFAT32(fs->fs_buffer, fatindex, nextcluster & 0x0fffffff);
|
||||
|
||||
/* Keep the top 4 bits */
|
||||
|
||||
val = FAT_GETFAT32(fs->fs_buffer, fatindex) & 0xf0000000;
|
||||
FAT_PUTFAT32(fs->fs_buffer, fatindex, val | (nextcluster & 0x0fffffff));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1228,12 +1242,14 @@ int32_t fat_extendchain(struct fat_mountpt_s *fs, uint32_t cluster)
|
||||
startsector = fat_getcluster(fs, newcluster);
|
||||
if (startsector == 0)
|
||||
{
|
||||
/* Found have found a free cluster break out*/
|
||||
/* Found have found a free cluster break out */
|
||||
|
||||
break;
|
||||
}
|
||||
else if (startsector < 0)
|
||||
{
|
||||
/* Some error occurred, return the error number */
|
||||
|
||||
return startsector;
|
||||
}
|
||||
|
||||
@ -1254,7 +1270,8 @@ int32_t fat_extendchain(struct fat_mountpt_s *fs, uint32_t cluster)
|
||||
ret = fat_putcluster(fs, newcluster, 0x0fffffff);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* An error occurred */
|
||||
/* An error occurred */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1290,7 +1307,7 @@ int32_t fat_extendchain(struct fat_mountpt_s *fs, uint32_t cluster)
|
||||
*
|
||||
* Desciption: Read the next directory entry from the sector in cache,
|
||||
* reading the next sector(s) in the cluster as necessary. This function
|
||||
* must return -ENOSPC if if fails because there are no further entries
|
||||
* must return -ENOSPC if it fails because there are no further entries
|
||||
* available in the directory.
|
||||
*
|
||||
****************************************************************************/
|
||||
@ -1368,6 +1385,7 @@ int fat_nextdirentry(struct fat_mountpt_s *fs, struct fs_fatdir_s *dir)
|
||||
|
||||
dir->fd_currcluster = cluster;
|
||||
dir->fd_currsector = fat_cluster2sector(fs, cluster);
|
||||
ndx = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1416,7 +1434,7 @@ int fat_dirtruncate(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo)
|
||||
/* Set the ARCHIVE attribute and update the write time */
|
||||
|
||||
DIR_PUTATTRIBUTES(direntry, FATATTR_ARCHIVE);
|
||||
|
||||
|
||||
writetime = fat_systime2fattime();
|
||||
DIR_PUTWRTTIME(direntry, writetime & 0xffff);
|
||||
DIR_PUTWRTDATE(direntry, writetime > 16);
|
||||
@ -1477,7 +1495,7 @@ int fat_fscacheflush(struct fat_mountpt_s *fs)
|
||||
int i;
|
||||
|
||||
for (i = fs->fs_fatnumfats; i >= 2; i--)
|
||||
{
|
||||
{
|
||||
fs->fs_currentsector += fs->fs_nfatsects;
|
||||
ret = fat_hwwrite(fs, fs->fs_buffer, fs->fs_currentsector, 1);
|
||||
if (ret < 0)
|
||||
@ -1591,31 +1609,32 @@ int fat_ffcacheread(struct fat_mountpt_s *fs, struct fat_file_s *ff, off_t secto
|
||||
*/
|
||||
|
||||
if (ff->ff_cachesector != sector || (ff->ff_bflags & FFBUFF_VALID) == 0)
|
||||
{
|
||||
/* We will need to read the new sector. First, flush the cached
|
||||
* sector if it is dirty.
|
||||
*/
|
||||
{
|
||||
/* We will need to read the new sector. First, flush the cached
|
||||
* sector if it is dirty.
|
||||
*/
|
||||
|
||||
ret = fat_ffcacheflush(fs, ff);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
ret = fat_ffcacheflush(fs, ff);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Then read the specified sector into the cache */
|
||||
/* Then read the specified sector into the cache */
|
||||
|
||||
ret = fat_hwread(fs, ff->ff_buffer, sector, 1);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
ret = fat_hwread(fs, ff->ff_buffer, sector, 1);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Update the cached sector number */
|
||||
/* Update the cached sector number */
|
||||
|
||||
ff->ff_cachesector = sector;
|
||||
ff->ff_bflags |= FFBUFF_VALID;
|
||||
ff->ff_cachesector = sector;
|
||||
ff->ff_bflags |= FFBUFF_VALID;
|
||||
}
|
||||
return OK;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -1632,21 +1651,22 @@ int fat_ffcacheinvalidate(struct fat_mountpt_s *fs, struct fat_file_s *ff)
|
||||
/* Is there anything valid in the buffer now? */
|
||||
|
||||
if ((ff->ff_bflags & FFBUFF_VALID) != 0)
|
||||
{
|
||||
/* We will invalidate the buffered sector */
|
||||
{
|
||||
/* We will invalidate the buffered sector */
|
||||
|
||||
ret = fat_ffcacheflush(fs, ff);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
ret = fat_ffcacheflush(fs, ff);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Then discard the current cache contents */
|
||||
/* Then discard the current cache contents */
|
||||
|
||||
ff->ff_bflags &= ~FFBUFF_VALID;
|
||||
ff->ff_cachesector = 0;
|
||||
ff->ff_bflags &= ~FFBUFF_VALID;
|
||||
ff->ff_cachesector = 0;
|
||||
}
|
||||
return OK;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -1694,6 +1714,7 @@ int fat_updatefsinfo(struct fat_mountpt_s *fs)
|
||||
fs->fs_fsidirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user