aboutsummaryrefslogtreecommitdiff
path: root/nuttx/fs/fat/fs_fat32.c
diff options
context:
space:
mode:
Diffstat (limited to 'nuttx/fs/fat/fs_fat32.c')
-rw-r--r--nuttx/fs/fat/fs_fat32.c171
1 files changed, 147 insertions, 24 deletions
diff --git a/nuttx/fs/fat/fs_fat32.c b/nuttx/fs/fat/fs_fat32.c
index 0c28cea67..c10c28a5c 100644
--- a/nuttx/fs/fat/fs_fat32.c
+++ b/nuttx/fs/fat/fs_fat32.c
@@ -1,7 +1,7 @@
/****************************************************************************
* fs/fat/fs_fat32.c
*
- * Copyright (C) 2007-2009, 2011-2012 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007-2009, 2011-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* References:
@@ -86,7 +86,9 @@ static ssize_t fat_write(FAR struct file *filep, const char *buffer,
size_t buflen);
static off_t fat_seek(FAR struct file *filep, off_t offset, int whence);
static int fat_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
+
static int fat_sync(FAR struct file *filep);
+static int fat_dup(FAR const struct file *oldp, FAR struct file *newp);
static int fat_opendir(struct inode *mountpt, const char *relpath,
struct fs_dirent_s *dir);
@@ -121,28 +123,30 @@ static int fat_stat(struct inode *mountpt, const char *relpath, struct stat
const struct mountpt_operations fat_operations =
{
- fat_open,
- fat_close,
- fat_read,
- fat_write,
- fat_seek,
- fat_ioctl,
- fat_sync,
-
- fat_opendir,
- NULL,
- fat_readdir,
- fat_rewinddir,
-
- fat_bind,
- fat_unbind,
- fat_statfs,
-
- fat_unlink,
- fat_mkdir,
- fat_rmdir,
- fat_rename,
- fat_stat
+ fat_open, /* open */
+ fat_close, /* close */
+ fat_read, /* read */
+ fat_write, /* write */
+ fat_seek, /* seek */
+ fat_ioctl, /* ioctl */
+
+ fat_sync, /* sync */
+ fat_dup, /* dup */
+
+ fat_opendir, /* opendir */
+ NULL, /* closedir */
+ fat_readdir, /* readdir */
+ fat_rewinddir, /* rewinddir */
+
+ fat_bind, /* bind */
+ fat_unbind, /* unbind */
+ fat_statfs, /* statfs */
+
+ fat_unlink, /* unlinke */
+ fat_mkdir, /* mkdir */
+ fat_rmdir, /* rmdir */
+ fat_rename, /* rename */
+ fat_stat /* stat */
};
/****************************************************************************
@@ -311,7 +315,6 @@ static int fat_open(FAR struct file *filep, const char *relpath,
/* Initialize the file private data (only need to initialize non-zero elements) */
- ff->ff_open = true;
ff->ff_oflags = oflags;
/* Save information that can be used later to recover the directory entry */
@@ -896,6 +899,7 @@ static off_t fat_seek(FAR struct file *filep, off_t offset, int whence)
DEBUGASSERT(fs != NULL);
/* Map the offset according to the whence option */
+
switch (whence)
{
case SEEK_SET: /* The offset is set to offset bytes. */
@@ -969,6 +973,7 @@ static off_t fat_seek(FAR struct file *filep, off_t offset, int whence)
ret = cluster;
goto errout_with_semaphore;
}
+
ff->ff_startcluster = cluster;
}
@@ -1231,6 +1236,124 @@ errout_with_semaphore:
}
/****************************************************************************
+ * Name: fat_dup
+ *
+ * Description: Duplicate open file data in the new file structure.
+ *
+ ****************************************************************************/
+
+static int fat_dup(FAR const struct file *oldp, FAR struct file *newp)
+{
+ FAR struct fat_mountpt_s *fs;
+ FAR struct fat_file_s *oldff;
+ FAR struct fat_file_s *newff;
+ int ret;
+
+ fvdbg("Dup %p->%p\n", oldp, newp);
+
+ /* Sanity checks */
+
+ DEBUGASSERT(oldp->f_priv != NULL &&
+ newp->f_priv == NULL &&
+ newp->f_inode != NULL);
+
+ /* Recover our private data from the struct file instance */
+
+ fs = (struct fat_mountpt_s *)oldp->f_inode->i_private;
+ DEBUGASSERT(fs != NULL);
+
+ /* Check if the mount is still healthy */
+
+ fat_semtake(fs);
+ ret = fat_checkmount(fs);
+ if (ret != OK)
+ {
+ goto errout_with_semaphore;
+ }
+
+ /* Recover the old private data from the old struct file instance */
+
+ oldff = oldp->f_priv;
+
+ /* Create a new instance of the file private date to describe the
+ * dup'ed file.
+ */
+
+ newff = (struct fat_file_s *)kmalloc(sizeof(struct fat_file_s));
+ if (!newff)
+ {
+ ret = -ENOMEM;
+ goto errout_with_semaphore;
+ }
+
+ /* Create a file buffer to support partial sector accesses */
+
+ newff->ff_buffer = (uint8_t*)fat_io_alloc(fs->fs_hwsectorsize);
+ if (!newff->ff_buffer)
+ {
+ ret = -ENOMEM;
+ goto errout_with_struct;
+ }
+
+ /* Copy the rest of the open open file state from the old file structure.
+ * There are some assumptions and potential issues here:
+ *
+ * 1) We assume that the higher level logic has copied the elements of
+ * the file structure, in particular, the file position.
+ * 2) There is a problem with ff_size if there are multiple opened
+ * file structures, each believing they know the size of the file.
+ * If one instance modifies the file length, then the new size of
+ * the opened file will be unknown to the other. That is a lurking
+ * bug!
+ *
+ * One good solution to this might be to add a refernce count to the
+ * file structure. Then, instead of dup'ing the whole structure
+ * as is done here, just increment the reference count on the
+ * structure. The would have to be integrated with open logic as
+ * well, however, so that the same file structure is re-used if the
+ * file is re-opened.
+ */
+
+ newff->ff_bflags = 0; /* File buffer flags */
+ newff->ff_oflags = oldff->ff_oflags; /* File open flags */
+ newff->ff_sectorsincluster = oldff->ff_sectorsincluster; /* Sectors remaining in cluster */
+ newff->ff_dirindex = oldff->ff_dirindex; /* Index to directory entry */
+ newff->ff_currentcluster = oldff->ff_currentcluster; /* Current cluster */
+ newff->ff_dirsector = oldff->ff_dirsector; /* Sector containing directory entry */
+ newff->ff_size = oldff->ff_size; /* Size of the file */
+ newff->ff_startcluster = oldff->ff_startcluster; /* Start cluster of file on media */
+ newff->ff_currentsector = oldff->ff_currentsector; /* Current sector */
+ newff->ff_cachesector = 0; /* Sector in file buffer */
+
+ /* Attach the private date to the struct file instance */
+
+ newp->f_priv = newff;
+
+ /* Then insert the new instance into the mountpoint structure.
+ * It needs to be there (1) to handle error conditions that effect
+ * all files, and (2) to inform the umount logic that we are busy
+ * (but a simple reference count could have done that).
+ */
+
+ newff->ff_next = fs->fs_head;
+ fs->fs_head = newff->ff_next;
+
+ fat_semgive(fs);
+ return OK;
+
+ /* Error exits -- goto's are nasty things, but they sure can make error
+ * handling a lot simpler.
+ */
+
+errout_with_struct:
+ kfree(newff);
+
+errout_with_semaphore:
+ fat_semgive(fs);
+ return ret;
+}
+
+/****************************************************************************
* Name: fat_opendir
*
* Description: Open a directory for read access