summaryrefslogtreecommitdiff
path: root/nuttx/fs
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2011-11-15 22:37:14 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2011-11-15 22:37:14 +0000
commit6e1ea39b8e41e8600506bc5325c25969de091ff3 (patch)
tree0506f37ccd6f7779514ea52f38ab89a75f7f0657 /nuttx/fs
parent4bf2eeec797de1c158143d33c572ef38e6ccc015 (diff)
downloadpx4-nuttx-6e1ea39b8e41e8600506bc5325c25969de091ff3.tar.gz
px4-nuttx-6e1ea39b8e41e8600506bc5325c25969de091ff3.tar.bz2
px4-nuttx-6e1ea39b8e41e8600506bc5325c25969de091ff3.zip
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
Diffstat (limited to 'nuttx/fs')
-rw-r--r--nuttx/fs/fat/fs_fat32.c15
-rw-r--r--nuttx/fs/fat/fs_fat32dirent.c106
2 files changed, 95 insertions, 26 deletions
diff --git a/nuttx/fs/fat/fs_fat32.c b/nuttx/fs/fat/fs_fat32.c
index f7818d551..b0ee57a18 100644
--- a/nuttx/fs/fat/fs_fat32.c
+++ b/nuttx/fs/fat/fs_fat32.c
@@ -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
{
diff --git a/nuttx/fs/fat/fs_fat32dirent.c b/nuttx/fs/fat/fs_fat32dirent.c
index a8c65b8de..54633004f 100644
--- a/nuttx/fs/fat/fs_fat32dirent.c
+++ b/nuttx/fs/fat/fs_fat32dirent.c
@@ -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 */
@@ -1909,6 +1912,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
*
* Desciption: Write the short directory entry name.
@@ -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;