Add FAT mkdir()

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@248 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo
2007-05-21 19:24:30 +00:00
parent d7b254d2e6
commit f0634f5588
6 changed files with 635 additions and 335 deletions
+1 -1
View File
@@ -142,6 +142,6 @@
* Added unlink(), mkdir(), rmdir(), and rename()
* Fixed several serious FAT errors with oflags handling (&& instead of &)
* Added FAT support for unlink() and rmdir()
* Added FAT support for unlink(), mkdir() and rmdir()
* Started m68322
+1 -1
View File
@@ -573,7 +573,7 @@ Other memory:
* Added unlink(), mkdir(), rmdir(), and rename()
* Fixed several serious FAT errors with oflags handling (&& instead of &)
* Added FAT support for unlink() and rmdir()
* Added FAT support for unlink(), mkdir() and rmdir()
* Started m68322
</pre></ul>
File diff suppressed because it is too large Load Diff
+177 -3
View File
@@ -1365,7 +1365,16 @@ static int fat_unlink(struct inode *mountpt, const char *relpath)
static int fat_mkdir(struct inode *mountpt, const char *relpath, mode_t mode)
{
struct fat_mountpt_s *fs;
int ret;
struct fat_dirinfo_s dirinfo;
ubyte *direntry;
ubyte *direntry2;
size_t parentsector;
ssize_t dirsector;
sint32 dircluster;
uint32 parentcluster;
uint32 crtime;
unsigned int i;
int ret;
/* Sanity checks */
@@ -1384,8 +1393,173 @@ static int fat_mkdir(struct inode *mountpt, const char *relpath, mode_t mode)
goto errout_with_semaphore;
}
#warning "fat_mkdir is not implemented"
ret = -ENOSYS;
/* Find the directory where the new directory should be created. */
ret = fat_finddirentry(fs, &dirinfo, relpath);
/* If anything exists at this location, then we fail with EEXIST */
if (ret == OK)
{
ret = -EEXIST;
goto errout_with_semaphore;
}
/* What we want to see is for fat_finddirentry to fail with -ENOENT.
* This error means that no failure occurred but that nothing exists
* with this name.
*/
if (ret != -ENOENT)
{
goto errout_with_semaphore;
}
/* NOTE: There is no check that dirinfo.fd_name contains the final
* directory name. We could be creating an intermediate directory
* in the full relpath.
*/
/* Allocate a directory entry for the new directory in this directory */
ret = fat_allocatedirentry(fs, &dirinfo);
if (ret != OK)
{
goto errout_with_semaphore;
}
parentsector = fs->fs_currentsector;
/* Allocate a cluster for new directory */
dircluster = fat_createchain(fs);
if (dircluster < 0)
{
ret = dircluster;
goto errout_with_semaphore;
}
else if (dircluster < 2)
{
ret = -ENOSPC;
goto errout_with_semaphore;
}
dirsector = fat_cluster2sector(fs, dircluster);
if (dirsector < 0)
{
ret = dirsector;
goto errout_with_semaphore;
}
/* Flush any existing, dirty data in fs_buffer (because we need
* it to create the directory entries.
*/
ret = fat_fscacheflush(fs);
if (ret < 0)
{
goto errout_with_semaphore;
}
/* Get a pointer to the first directory entry in the sector */
direntry = fs->fs_buffer;
/* Now erase the contents of fs_buffer */
fs->fs_currentsector = dirsector;
memset(direntry, 0, fs->fs_hwsectorsize);
/* Now clear all sectors in the new directory cluster (except for the first) */
for (i = 1; i < fs->fs_fatsecperclus; i++)
{
ret = fat_hwwrite(fs, direntry, ++dirsector, 1);
if (ret < 0)
{
goto errout_with_semaphore;
}
}
/* Now create the "." directory entry in the first directory slot */
memset(&direntry[DIR_NAME], ' ', 8+3);
direntry[DIR_NAME] = '.';
DIR_PUTATTRIBUTES(direntry, FATATTR_DIRECTORY);
crtime = fat_gettime();
DIR_PUTCRTIME(direntry, crtime & 0xffff);
DIR_PUTWRTTIME(direntry, crtime & 0xffff);
DIR_PUTCRDATE(direntry, crtime >> 16);
DIR_PUTWRTDATE(direntry, crtime >> 16);
/* Create ".." directory entry in the second directory slot */
direntry2 = direntry + 32;
/* So far, the two entries are nearly the same */
memcpy(direntry2, direntry, 32);
direntry2[DIR_NAME+1] = '.';
/* Now add the cluster information to both directory entries */
DIR_PUTFSTCLUSTHI(direntry, dircluster >> 16);
DIR_PUTFSTCLUSTLO(direntry, dircluster);
parentcluster = dirinfo.fd_startcluster;
if (fs->fs_type != FSTYPE_FAT32 && parentcluster == fs->fs_rootbase)
{
parentcluster = 0;
}
DIR_PUTFSTCLUSTHI(direntry2, parentcluster >> 16);
DIR_PUTFSTCLUSTLO(direntry2, parentcluster);
/* Save the first sector of the directory cluster and re-read
* the parentsector
*/
fs->fs_dirty = TRUE;
ret = fat_fscacheread(fs, parentsector);
if (ret < 0)
{
goto errout_with_semaphore;
}
/* Initialize the new entry directory entry in the parent directory */
direntry = dirinfo.fd_entry;
memset(direntry, 0, 32);
memcpy(direntry, dirinfo.fd_name, 8+3);
#ifdef CONFIG_FLAT_LCNAMES
DIR_PUTNTRES(direntry, dirinfo.fd_ntflags);
#endif
DIR_PUTATTRIBUTES(dirinfo.fd_entry, FATATTR_DIRECTORY);
/* Same creation time as for . and .. */
DIR_PUTCRTIME(dirinfo.fd_entry, crtime & 0xffff);
DIR_PUTWRTTIME(dirinfo.fd_entry, crtime & 0xffff);
DIR_PUTCRDATE(dirinfo.fd_entry, crtime >> 16);
DIR_PUTWRTDATE(dirinfo.fd_entry, crtime >> 16);
/* Set subdirectory start cluster */
DIR_PUTFSTCLUSTLO(dirinfo.fd_entry, dircluster);
DIR_PUTFSTCLUSTHI(dirinfo.fd_entry, dircluster >> 16);
/* Now update the FAT32 FSINFO sector */
fs->fs_dirty = TRUE;
ret = fat_updatefsinfo(fs);
if (ret < 0)
{
goto errout_with_semaphore;
}
fat_semgive(fs);
return OK;
errout_with_semaphore:
fat_semgive(fs);
+2
View File
@@ -559,6 +559,7 @@ EXTERN sint32 fat_extendchain(struct fat_mountpt_s *fs, uint32 cluster);
EXTERN int fat_nextdirentry(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo);
EXTERN int fat_finddirentry(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo,
const char *path);
EXTERN int fat_allocatedirentry(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo);
/* File creation and removal helpers */
@@ -568,6 +569,7 @@ EXTERN int fat_remove(struct fat_mountpt_s *fs, const char *relpath, boolean
/* Mountpoint and file buffer cache (for partial sector accesses) */
EXTERN int fat_fscacheflush(struct fat_mountpt_s *fs);
EXTERN int fat_fscacheread(struct fat_mountpt_s *fs, size_t sector);
EXTERN int fat_ffcacheflush(struct fat_mountpt_s *fs, struct fat_file_s *ff);
EXTERN int fat_ffcacheread(struct fat_mountpt_s *fs, struct fat_file_s *ff, size_t sector);
+171 -171
View File
@@ -83,56 +83,6 @@
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: fat_fscacheflush
*
* Desciption: Flush any dirty sectors as necessary
*
****************************************************************************/
static int fat_fscacheflush(struct fat_mountpt_s *fs)
{
int ret;
/* Check if the fs_buffer is dirty. In this case, we will write back the
* contents of fs_buffer.
*/
if (fs->fs_dirty)
{
/* Write the dirty sector */
ret = fat_hwwrite(fs, fs->fs_buffer, fs->fs_currentsector, 1);
if (ret < 0)
{
return ret;
}
/* Does the sector lie in the FAT region? */
if (fs->fs_currentsector < fs->fs_fatbase + fs->fs_fatsize)
{
/* Yes, then make the change in the FAT copy as well */
int i;
for (i = fs->fs_fatnumfats; i >= 2; i--)
{
fs->fs_currentsector += fs->fs_fatsize;
ret = fat_hwwrite(fs, fs->fs_buffer, fs->fs_currentsector, 1);
if (ret < 0)
{
return ret;
}
}
}
/* No longer dirty */
fs->fs_dirty = FALSE;
}
return OK;
}
/****************************************************************************
* Name: fat_path2dirname
*
@@ -409,127 +359,6 @@ static inline int fat_dirname2path(char *path, struct fat_dirinfo_s *dirinfo)
return OK;
}
/****************************************************************************
* Name: fat_allocatedirentry
*
* Desciption: Find a free directory entry
*
****************************************************************************/
static int fat_allocatedirentry(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo)
{
sint32 cluster;
size_t sector;
ubyte *direntry;
ubyte ch;
int ret;
int i;
/* Re-initialize directory object */
cluster = dirinfo->fd_startcluster;
if (cluster)
{
/* Cluster chain can be extended */
dirinfo->fd_currcluster = cluster;
dirinfo->fd_currsector = fat_cluster2sector(fs, cluster);
}
else
{
/* Fixed size FAT12/16 root directory is at fixxed offset/size */
dirinfo->fd_currsector = fs->fs_rootbase;
}
dirinfo->fd_index = 0;
for (;;)
{
unsigned int dirindex;
/* Read the directory sector into fs_buffer */
ret = fat_fscacheread(fs, dirinfo->fd_currsector);
if (ret < 0)
{
return ret;
}
/* Get a pointer to the entry at fd_index */
dirindex = (dirinfo->fd_index & DIRSEC_NDXMASK(fs)) * 32;
direntry = &fs->fs_buffer[dirindex];
/* Check if this directory entry is empty */
ch = direntry[DIR_NAME];
if (ch == DIR0_ALLEMPTY || ch == DIR0_EMPTY)
{
/* It is empty -- we have found a directory entry */
dirinfo->fd_entry = direntry;
return OK;
}
ret = fat_nextdirentry(fs, dirinfo);
if (ret < 0)
{
return ret;
}
}
/* If we get here, then we have reached the end of the directory table
* in this sector without finding a free directory enty.
*
* It this is a fixed size dirctory entry, then this is an error.
* Otherwise, we can try to extend the directory cluster chain to
* make space for the new directory entry.
*/
if (!cluster)
{
/* The size is fixed */
return -ENOSPC;
}
/* Try to extend the cluster chain for this directory */
cluster = fat_extendchain(fs, dirinfo->fd_currcluster);
if (cluster < 0)
{
return cluster;
}
/* Flush out any cached date in fs_buffer.. we are going to use
* it to initialize the new directory cluster.
*/
ret = fat_fscacheflush(fs);
if (ret < 0)
{
return ret;
}
/* Clear all sectors comprising the new directory cluster */
fs->fs_currentsector = fat_cluster2sector(fs, cluster);
memset(fs->fs_buffer, 0, fs->fs_hwsectorsize);
sector = sector;
for (i = fs->fs_fatsecperclus; i; i--)
{
ret = fat_hwwrite(fs, fs->fs_buffer, sector, 1);
if ( ret < 0)
{
return ret;
}
sector++;
}
dirinfo->fd_entry = fs->fs_buffer;
return OK;
}
/****************************************************************************
* Name: fat_checkfsinfo
*
@@ -1823,6 +1652,127 @@ int fat_finddirentry(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo,
}
}
/****************************************************************************
* Name: fat_allocatedirentry
*
* Desciption: Find a free directory entry
*
****************************************************************************/
int fat_allocatedirentry(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo)
{
sint32 cluster;
size_t sector;
ubyte *direntry;
ubyte ch;
int ret;
int i;
/* Re-initialize directory object */
cluster = dirinfo->fd_startcluster;
if (cluster)
{
/* Cluster chain can be extended */
dirinfo->fd_currcluster = cluster;
dirinfo->fd_currsector = fat_cluster2sector(fs, cluster);
}
else
{
/* Fixed size FAT12/16 root directory is at fixxed offset/size */
dirinfo->fd_currsector = fs->fs_rootbase;
}
dirinfo->fd_index = 0;
for (;;)
{
unsigned int dirindex;
/* Read the directory sector into fs_buffer */
ret = fat_fscacheread(fs, dirinfo->fd_currsector);
if (ret < 0)
{
return ret;
}
/* Get a pointer to the entry at fd_index */
dirindex = (dirinfo->fd_index & DIRSEC_NDXMASK(fs)) * 32;
direntry = &fs->fs_buffer[dirindex];
/* Check if this directory entry is empty */
ch = direntry[DIR_NAME];
if (ch == DIR0_ALLEMPTY || ch == DIR0_EMPTY)
{
/* It is empty -- we have found a directory entry */
dirinfo->fd_entry = direntry;
return OK;
}
ret = fat_nextdirentry(fs, dirinfo);
if (ret < 0)
{
return ret;
}
}
/* If we get here, then we have reached the end of the directory table
* in this sector without finding a free directory enty.
*
* It this is a fixed size dirctory entry, then this is an error.
* Otherwise, we can try to extend the directory cluster chain to
* make space for the new directory entry.
*/
if (!cluster)
{
/* The size is fixed */
return -ENOSPC;
}
/* Try to extend the cluster chain for this directory */
cluster = fat_extendchain(fs, dirinfo->fd_currcluster);
if (cluster < 0)
{
return cluster;
}
/* Flush out any cached date in fs_buffer.. we are going to use
* it to initialize the new directory cluster.
*/
ret = fat_fscacheflush(fs);
if (ret < 0)
{
return ret;
}
/* Clear all sectors comprising the new directory cluster */
fs->fs_currentsector = fat_cluster2sector(fs, cluster);
memset(fs->fs_buffer, 0, fs->fs_hwsectorsize);
sector = sector;
for (i = fs->fs_fatsecperclus; i; i--)
{
ret = fat_hwwrite(fs, fs->fs_buffer, sector, 1);
if ( ret < 0)
{
return ret;
}
sector++;
}
dirinfo->fd_entry = fs->fs_buffer;
return OK;
}
/****************************************************************************
* Name: fat_dirtruncate
*
@@ -2112,6 +2062,56 @@ int fat_remove(struct fat_mountpt_s *fs, const char *relpath, boolean directory)
return OK;
}
/****************************************************************************
* Name: fat_fscacheflush
*
* Desciption: Flush any dirty sector if fs_buffer as necessary
*
****************************************************************************/
int fat_fscacheflush(struct fat_mountpt_s *fs)
{
int ret;
/* Check if the fs_buffer is dirty. In this case, we will write back the
* contents of fs_buffer.
*/
if (fs->fs_dirty)
{
/* Write the dirty sector */
ret = fat_hwwrite(fs, fs->fs_buffer, fs->fs_currentsector, 1);
if (ret < 0)
{
return ret;
}
/* Does the sector lie in the FAT region? */
if (fs->fs_currentsector < fs->fs_fatbase + fs->fs_fatsize)
{
/* Yes, then make the change in the FAT copy as well */
int i;
for (i = fs->fs_fatnumfats; i >= 2; i--)
{
fs->fs_currentsector += fs->fs_fatsize;
ret = fat_hwwrite(fs, fs->fs_buffer, fs->fs_currentsector, 1);
if (ret < 0)
{
return ret;
}
}
}
/* No longer dirty */
fs->fs_dirty = FALSE;
}
return OK;
}
/****************************************************************************
* Name: fat_fscacheread
*