Fix an error in FAT needed for interoperability with Windows when access first entry in root directory
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4093 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
0fe0a10e9f
commit
bdd0e9e973
@ -2210,3 +2210,7 @@
|
||||
* drivers/mmcsd0/mmcsd_sdio.c: Increase capacity variable from size_t
|
||||
to uin64_t (if available) so that SD cards with capacities greater
|
||||
than 4Gb can be supported.
|
||||
* fs/fat/fs_fat32dirent.c: The root directory structure is different
|
||||
from other directories. When formatted by Windows, it is not initialized
|
||||
at all. Some additional special handling is required to initialize the
|
||||
root directory entry to interoperate correctly with windows.
|
||||
|
12
TODO
12
TODO
@ -1,4 +1,4 @@
|
||||
NuttX TODO List (Last updated October 3, 2011)
|
||||
NuttX TODO List (Last updated November 15, 2011)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This file summarizes known NuttX bugs, limitations, inconsistencies with
|
||||
@ -16,7 +16,7 @@ nuttx/
|
||||
(16) Network (net/, drivers/net)
|
||||
(2) USB (drivers/usbdev, drivers/usbhost)
|
||||
(7) Libraries (lib/)
|
||||
(9) File system/Generic drivers (fs/, drivers/)
|
||||
(10) File system/Generic drivers (fs/, drivers/)
|
||||
(2) Graphics subystem (graphics/)
|
||||
(1) Pascal add-on (pcode/)
|
||||
(1) Documentation (Documentation/)
|
||||
@ -501,6 +501,14 @@ o File system / Generic drivers (fs/, drivers/)
|
||||
Status: Open
|
||||
Priority: Medium
|
||||
|
||||
Description: mkfatfs() does not create the "." directory entry (all directories)
|
||||
or the ".." directory entry (all directories except for the root
|
||||
directory). NuttX doesn't care about these entries, but this will
|
||||
probably make a FAT filesystem formatted on NuttX unusable under
|
||||
Windows.
|
||||
Status: Open
|
||||
Priority: High
|
||||
|
||||
o Graphics subystem (graphics/)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -148,7 +148,7 @@
|
||||
|
||||
/* Context switching system calls ***************************************************/
|
||||
|
||||
/* SYS call 0:
|
||||
/* SYS call 1:
|
||||
*
|
||||
* void up_fullcontextrestore(uint32_t *restoreregs) __attribute__ ((noreturn));
|
||||
*/
|
||||
@ -157,7 +157,7 @@
|
||||
#define up_fullcontextrestore(restoreregs) \
|
||||
(void)sys_call1(SYS_restore_context, (uintptr_t)restoreregs)
|
||||
|
||||
/* SYS call 1:
|
||||
/* SYS call 2:
|
||||
*
|
||||
* void up_switchcontext(uint32_t *saveregs, uint32_t *restoreregs);
|
||||
*/
|
||||
|
@ -1295,12 +1295,13 @@ static int fat_opendir(struct inode *mountpt, const char *relpath, struct fs_dir
|
||||
else if ((DIR_GETATTRIBUTES(direntry) & FATATTR_DIRECTORY) == 0)
|
||||
{
|
||||
/* The entry is not a directory */
|
||||
|
||||
ret = -ENOTDIR;
|
||||
goto errout_with_semaphore;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The entry is a directory */
|
||||
/* The entry is a directory (but not the root directory) */
|
||||
|
||||
dir->u.fat.fd_startcluster =
|
||||
((uint32_t)DIR_GETFSTCLUSTHI(direntry) << 16) |
|
||||
@ -1492,7 +1493,9 @@ static int fat_rewinddir(struct inode *mountpt, struct fs_dirent_s *dir)
|
||||
goto errout_with_semaphore;
|
||||
}
|
||||
|
||||
/* Check if this is the root directory */
|
||||
/* Check if this is the root directory. If it is the root directory, we
|
||||
* reset the fd_index to 1, skipping over the initial, unused entry.
|
||||
*/
|
||||
|
||||
if (fs->fs_type != FSTYPE_FAT32 &&
|
||||
dir->u.fat.fd_startcluster == 0)
|
||||
@ -1501,7 +1504,7 @@ static int fat_rewinddir(struct inode *mountpt, struct fs_dirent_s *dir)
|
||||
|
||||
dir->u.fat.fd_currcluster = 0;
|
||||
dir->u.fat.fd_currsector = fs->fs_rootbase;
|
||||
dir->u.fat.fd_index = 0;
|
||||
dir->u.fat.fd_index = 1;
|
||||
}
|
||||
else if (fs->fs_type == FSTYPE_FAT32 &&
|
||||
dir->u.fat.fd_startcluster == fs->fs_rootbase)
|
||||
@ -1510,10 +1513,12 @@ static int fat_rewinddir(struct inode *mountpt, struct fs_dirent_s *dir)
|
||||
|
||||
dir->u.fat.fd_currcluster = dir->u.fat.fd_startcluster;
|
||||
dir->u.fat.fd_currsector = fat_cluster2sector(fs, fs->fs_rootbase);
|
||||
dir->u.fat.fd_index = 0;
|
||||
dir->u.fat.fd_index = 1;
|
||||
}
|
||||
|
||||
/* This is not the root directory */
|
||||
/* This is not the root directory. Here the fd_index is set to 2, skipping over
|
||||
* both the "." and ".." entries.
|
||||
*/
|
||||
|
||||
else
|
||||
{
|
||||
|
@ -144,6 +144,8 @@ static inline int fat_getsfname(uint8_t *direntry, char *buffer,
|
||||
static void fat_getlfnchunk(uint8_t *chunk, uint8_t *dest, int nchunk);
|
||||
static inline int fat_getlfname(struct fat_mountpt_s *fs, struct fs_dirent_s *dir);
|
||||
#endif
|
||||
static int fat_dirverify(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo,
|
||||
uint16_t offset);
|
||||
static int fat_putsfname(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo);
|
||||
#ifdef CONFIG_FAT_LFN
|
||||
static void fat_initlfname(uint8_t *chunk, int nchunk);
|
||||
@ -792,13 +794,14 @@ static inline int fat_findalias(struct fat_mountpt_s *fs,
|
||||
|
||||
memcpy(&tmpinfo, dirinfo, sizeof(struct fat_dirinfo_s));
|
||||
|
||||
/* Then re-initialize to the beginning of the current directory (skipping
|
||||
* '.' and '..').
|
||||
/* Then re-initialize to the beginning of the current directory, skipping
|
||||
* over the first entry (unused in the root directory and '.' entry in other
|
||||
* directories).
|
||||
*/
|
||||
|
||||
tmpinfo.dir.fd_startcluster = tmpinfo.dir.fd_currcluster;
|
||||
tmpinfo.dir.fd_currsector = tmpinfo.fd_seq.ds_startsector;
|
||||
tmpinfo.dir.fd_index = 2;
|
||||
tmpinfo.dir.fd_index = 1;
|
||||
|
||||
/* Search for the single short file name directory entry in this directory */
|
||||
|
||||
@ -1908,6 +1911,56 @@ static inline int fat_getlfname(struct fat_mountpt_s *fs, struct fs_dirent_s *di
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: fat_dirverify
|
||||
*
|
||||
* Desciption:
|
||||
* Verify that every entry preceding this one is marked with something
|
||||
* other than DIR0_ALLEMPTY. This is necessary only in the root directory
|
||||
* of freshly formatted volumes. In that case, all entries are set to
|
||||
* zero.
|
||||
*
|
||||
* This function also assures that the sector containing the entry is in
|
||||
* the sector cache.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int fat_dirverify(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo,
|
||||
uint16_t offset)
|
||||
{
|
||||
uint8_t *direntry;
|
||||
uint16_t i;
|
||||
int ret;
|
||||
|
||||
/* Make sure that the sector containing the directory entry is in the sector
|
||||
* cache.
|
||||
*/
|
||||
|
||||
ret = fat_fscacheread(fs, dirinfo->dir.fd_currsector);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Check every entry preceding this one */
|
||||
|
||||
for (i = 0; i < offset; i += DIR_SIZE)
|
||||
{
|
||||
/* Is the rest of the directory marked empty? */
|
||||
|
||||
direntry = &fs->fs_buffer[i];
|
||||
if (direntry[DIR_NAME] == DIR0_ALLEMPTY)
|
||||
{
|
||||
/* Then mark the just the entry as empty */
|
||||
|
||||
fs->fs_dirty = true;
|
||||
direntry[DIR_NAME] = DIR0_EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: fat_putsfname
|
||||
*
|
||||
@ -1921,6 +1974,8 @@ 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);
|
||||
#ifdef CONFIG_FAT_LCNAMES
|
||||
DIR_PUTNTRES(direntry, dirinfo->fd_ntflags);
|
||||
@ -2012,6 +2067,12 @@ static int fat_putlfname(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo
|
||||
int namelen;
|
||||
int ret;
|
||||
|
||||
/* Some special handling in case we are writing the first entry of the
|
||||
* root directory in a freshly formatted volume.
|
||||
*/
|
||||
|
||||
(void)fat_dirverify(fs, dirinfo, dirinfo->fd_seq.ds_lfnoffset);
|
||||
|
||||
/* Get the length of the long file name (size of the fd_lfname array is
|
||||
* LDIR_MAXFNAME+1 we do not have to check the length of the string).
|
||||
* NOTE that remainder is conditionally incremented to include the NUL
|
||||
@ -2065,18 +2126,11 @@ static int fat_putlfname(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo
|
||||
|
||||
seqno = LDIR0_LAST | nentries;
|
||||
|
||||
/* Make sure that the sector containing the "last" long file name entry
|
||||
* is in the sector cache (it probably is not).
|
||||
/* Now loop, writing each long file name entry. We know that the sector
|
||||
* is in the sector cache because fat_dirverify() assures us that that is
|
||||
* so.
|
||||
*/
|
||||
|
||||
ret = fat_fscacheread(fs, dirinfo->dir.fd_currsector);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Now loop, writing each long file name entry */
|
||||
|
||||
for (;;)
|
||||
{
|
||||
/* Get the string offset associated with the directory entry. */
|
||||
@ -2201,6 +2255,12 @@ static int fat_putsfdirentry(struct fat_mountpt_s *fs,
|
||||
{
|
||||
uint8_t *direntry;
|
||||
|
||||
/* Some special handling in case we are writing the first entry of the
|
||||
* root directory in a freshly formatted volume.
|
||||
*/
|
||||
|
||||
(void)fat_dirverify(fs, dirinfo, dirinfo->fd_seq.ds_offset);
|
||||
|
||||
/* Initialize the 32-byte directory entry */
|
||||
|
||||
direntry = &fs->fs_buffer[dirinfo->fd_seq.ds_offset];
|
||||
@ -2276,11 +2336,11 @@ int fat_finddirentry(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo,
|
||||
dirinfo->dir.fd_currsector = cluster;
|
||||
}
|
||||
|
||||
/* fd_index is the index into the current directory table. Skipping over
|
||||
* the '.' and '..' entries.
|
||||
/* fd_index is the index into the current directory table. It is set to one
|
||||
* to skip over the first, unused entry in the root directory.
|
||||
*/
|
||||
|
||||
dirinfo->dir.fd_index = 2;
|
||||
dirinfo->dir.fd_index = 1;
|
||||
|
||||
/* If no path was provided, then the root directory must be exactly what
|
||||
* the caller is looking for.
|
||||
@ -2377,7 +2437,10 @@ int fat_finddirentry(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo,
|
||||
((uint32_t)DIR_GETFSTCLUSTHI(direntry) << 16) |
|
||||
DIR_GETFSTCLUSTLO(direntry);
|
||||
|
||||
/* Then restart scanning at the new directory */
|
||||
/* Then restart scanning at the new directory, skipping over both the
|
||||
* '.' and '..' entries that exist in all directories EXCEPT the root
|
||||
* directory.
|
||||
*/
|
||||
|
||||
dirinfo->dir.fd_startcluster = cluster;
|
||||
dirinfo->dir.fd_currcluster = cluster;
|
||||
@ -2426,9 +2489,9 @@ int fat_allocatedirentry(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo
|
||||
dirinfo->dir.fd_currsector = fs->fs_rootbase;
|
||||
}
|
||||
|
||||
/* Skip over the '.' and '..' entries */
|
||||
/* Skip over the first, unused entry in the root directory. */
|
||||
|
||||
dirinfo->dir.fd_index = 2;
|
||||
dirinfo->dir.fd_index = 1;
|
||||
|
||||
/* Is this a path segment a long or a short file. Was a long file
|
||||
* name parsed?
|
||||
@ -2835,8 +2898,9 @@ int fat_remove(struct fat_mountpt_s *fs, const char *relpath, bool directory)
|
||||
return -EISDIR;
|
||||
}
|
||||
|
||||
/* We are asked to delete a directory. Check if this
|
||||
* sub-directory is empty
|
||||
/* We are asked to delete a directory. Check if this sub-directory is
|
||||
* empty (i.e., that there are no valid entries other than the initial
|
||||
* '.' and '..' entries).
|
||||
*/
|
||||
|
||||
dirinfo.dir.fd_currcluster = dircluster;
|
||||
|
Loading…
Reference in New Issue
Block a user