aboutsummaryrefslogtreecommitdiff
path: root/nuttx/fs/nxffs/nxffs_inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'nuttx/fs/nxffs/nxffs_inode.c')
-rw-r--r--nuttx/fs/nxffs/nxffs_inode.c502
1 files changed, 502 insertions, 0 deletions
diff --git a/nuttx/fs/nxffs/nxffs_inode.c b/nuttx/fs/nxffs/nxffs_inode.c
new file mode 100644
index 000000000..505a6c686
--- /dev/null
+++ b/nuttx/fs/nxffs/nxffs_inode.c
@@ -0,0 +1,502 @@
+/****************************************************************************
+ * fs/nxffs/nxffs_inode.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * References: Linux/Documentation/filesystems/romfs.txt
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <string.h>
+#include <crc32.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/kmalloc.h>
+#include <nuttx/mtd.h>
+
+#include "nxffs.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Variables
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nxffs_rdentry
+ *
+ * Description:
+ * Read the inode entry at this offset. Called only from nxffs_nextentry().
+ *
+ * Input Parameters:
+ * volume - Describes the current volume.
+ * offset - The byte offset from the beginning of FLASH where the inode
+ * header is expected.
+ * entry - A memory location to return the expanded inode header
+ * information.
+ *
+ * Returned Value:
+ * Zero on success. Otherwise, a negated errno value is returned
+ * indicating the nature of the failure.
+ *
+ * On return, the
+ *
+ ****************************************************************************/
+
+static int nxffs_rdentry(FAR struct nxffs_volume_s *volume, off_t offset,
+ FAR struct nxffs_entry_s *entry)
+{
+ struct nxffs_inode_s inode;
+ uint32_t ecrc;
+ uint32_t crc;
+ uint8_t state;
+ int namlen;
+ int ret;
+
+ DEBUGASSERT(volume && entry);
+ memset(entry, 0, sizeof(struct nxffs_entry_s));
+
+ /* Read the header at the FLASH offset */
+
+ nxffs_ioseek(volume, offset);
+ memcpy(&inode, &volume->cache[volume->iooffset], SIZEOF_NXFFS_INODE_HDR);
+
+ /* Check if the file state is recognized. */
+
+ state = inode.state;
+ if (state != INODE_STATE_FILE && state != INODE_STATE_DELETED)
+ {
+ /* This can't be a valid inode.. don't bother with the rest */
+
+ ret = -ENOENT;
+ goto errout_no_offset;
+ }
+
+ /* Copy the packed header into the user-friendly buffer */
+
+ entry->hoffset = offset;
+ entry->noffset = nxffs_rdle32(inode.noffs);
+ entry->doffset = nxffs_rdle32(inode.doffs);
+ entry->utc = nxffs_rdle32(inode.utc);
+ entry->datlen = nxffs_rdle32(inode.datlen);
+
+ /* Modify the packed header and perform the (partial) CRC calculation */
+
+ ecrc = nxffs_rdle32(inode.crc);
+ inode.state = CONFIG_NXFFS_ERASEDSTATE;
+ memset(inode.crc, 0, 4);
+ crc = crc32((FAR const uint8_t *)&inode, SIZEOF_NXFFS_INODE_HDR);
+
+ /* Allocate memory to hold the variable-length file name */
+
+ namlen = inode.namlen;
+ entry->name = (FAR char *)kmalloc(namlen + 1);
+ if (!entry->name)
+ {
+ fdbg("Failed to allocate name, namlen: %d\n", namlen);
+ ret = -ENOMEM;
+ goto errout_no_offset;
+ }
+
+ /* Seek to the expected location of the name in FLASH */
+
+ nxffs_ioseek(volume, entry->noffset);
+
+ /* Make sure that the block is in memory (the name may not be in the
+ * same block as the inode header.
+ */
+
+ ret = nxffs_rdcache(volume, volume->ioblock);
+ if (ret < 0)
+ {
+ fdbg("nxffsx_rdcache failed: %d\n", -ret);
+ goto errout_with_name;
+ }
+
+ /* Read the file name from the expected offset in FLASH */
+
+ memcpy(entry->name, &volume->cache[volume->iooffset], namlen);
+ entry->name[namlen] = '\0';
+
+ /* Finish the CRC calculation and verify the entry */
+
+ crc = crc32part((FAR const uint8_t *)entry->name, namlen, crc);
+ if (crc != ecrc)
+ {
+ fdbg("CRC entry: %08x CRC calculated: %08x\n", ecrc, crc);
+ ret = -EIO;
+ goto errout_with_name;
+ }
+
+ /* We have a good inode header.. but it still could a deleted file.
+ * Check the file state.
+ */
+
+ if (state != INODE_STATE_FILE)
+ {
+ /* It is a deleted file. But still, the data offset and the
+ * start size are good so we can use this information to advance
+ * further in FLASH memory and reduce the search time.
+ */
+
+ offset = nxffs_inodeend(volume, entry);
+ nxffs_freeentry(entry);
+ ret = -ENOENT;
+ goto errout;
+ }
+
+ /* Everything is good.. leave the offset pointing to the valid inode
+ * header.
+ */
+
+ return OK;
+
+ /* On errors where we are suspicious of the validity of the inode header,
+ * we need to increment the file position to just after the "good" magic
+ * word.
+ */
+
+errout_with_name:
+ nxffs_freeentry(entry);
+errout_no_offset:
+ offset += NXFFS_MAGICSIZE;
+errout:
+ nxffs_ioseek(volume, offset);
+ return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nxffs_freeentry
+ *
+ * Description:
+ * The inode values returned by nxffs_nextentry() include allocated memory
+ * (specifically, the file name string). This function should be called
+ * to dispose of that memory when the inode entry is no longer needed.
+ *
+ * Note that the nxffs_entry_s containing structure is not freed. The
+ * caller may call kfree upon return of this function if necessary to
+ * free the entry container.
+ *
+ * Input parameters:
+ * entry - The entry to be freed.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+void nxffs_freeentry(FAR struct nxffs_entry_s *entry)
+{
+ if (entry->name)
+ {
+ kfree(entry->name);
+ entry->name = NULL;
+ }
+}
+
+/****************************************************************************
+ * Name: nxffs_nextentry
+ *
+ * Description:
+ * Search for the next valid inode starting at the provided FLASH offset.
+ *
+ * Input Parameters:
+ * volume - Describes the NXFFS volume.
+ * offset - The FLASH memory offset to begin searching.
+ * entry - A pointer to memory provided by the caller in which to return
+ * the inode description.
+ *
+ * Returned Value:
+ * Zero is returned on success. Otherwise, a negated errno is returned
+ * that indicates the nature of the failure.
+ *
+ ****************************************************************************/
+
+int nxffs_nextentry(FAR struct nxffs_volume_s *volume, off_t offset,
+ FAR struct nxffs_entry_s *entry)
+{
+ int nmagic;
+ int ch;
+ int nerased;
+ int ret;
+
+ /* Seek to the first FLASH offset provided by the caller. */
+
+ nxffs_ioseek(volume, offset);
+
+ /* Then begin searching */
+
+ nerased = 0;
+ nmagic = 0;
+ for (;;)
+ {
+ /* Read the next character */
+
+ ch = nxffs_getc(volume, SIZEOF_NXFFS_INODE_HDR - nmagic);
+ if (ch < 0)
+ {
+ fvdbg("nxffs_getc failed: %d\n", -ch);
+ return ch;
+ }
+
+ /* Check for another erased byte */
+
+ else if (ch == CONFIG_NXFFS_ERASEDSTATE)
+ {
+ /* If we have encountered NXFFS_NERASED number of consecutive
+ * erased bytes, then presume we have reached the end of valid
+ * data.
+ */
+
+ if (++nerased >= NXFFS_NERASED)
+ {
+ fvdbg("No entry found\n");
+ return -ENOENT;
+ }
+ }
+ else
+ {
+ nerased = 0;
+
+ /* Check for the magic sequence indicating the start of an NXFFS
+ * inode. There is the possibility of this magic sequnce occurring
+ * in FLASH data. However, the header CRC should distinguish
+ * between real NXFFS inode headers and such false alarms.
+ */
+
+ if (ch != g_inodemagic[nmagic])
+ {
+ /* Ooops... this is the not the right character for the magic
+ * Sequence. Check if we need to restart or to cancel the sequence:
+ */
+
+ if (ch == g_inodemagic[0])
+ {
+ nmagic = 1;
+ }
+ else
+ {
+ nmagic = 0;
+ }
+ }
+ else if (nmagic < NXFFS_MAGICSIZE - 1)
+ {
+ /* We have one more character in the magic sequence */
+
+ nmagic++;
+ }
+
+ /* We have found the magic sequence in the FLASH data that may
+ * indicate the beginning of an NXFFS inode.
+ */
+
+ else
+ {
+ /* The the FLASH offset where we found the matching magic number */
+
+ offset = nxffs_iotell(volume) - NXFFS_MAGICSIZE;
+
+ /* Try to extract the inode header from that position */
+
+ ret = nxffs_rdentry(volume, offset, entry);
+ if (ret == OK)
+ {
+ fvdbg("Found a valid fileheader, offset: %d\n", offset);
+ return OK;
+ }
+
+ /* False alarm.. keep looking */
+
+ nmagic = 0;
+ }
+ }
+ }
+
+ /* We won't get here, but to keep some compilers happy: */
+
+ return -ENOENT;
+}
+
+/****************************************************************************
+ * Name: nxffs_findinode
+ *
+ * Description:
+ * Search for an inode with the provided name starting with the first
+ * valid inode and proceeding to the end FLASH or until the matching
+ * inode is found.
+ *
+ * Input Parameters:
+ * volume - Describes the NXFFS volume
+ * name - The name of the inode to find
+ * entry - The location to return information about the inode.
+ *
+ * Returned Value:
+ * Zero is returned on success. Otherwise, a negated errno is returned
+ * that indicates the nature of the failure.
+ *
+ ****************************************************************************/
+
+int nxffs_findinode(FAR struct nxffs_volume_s *volume, FAR const char *name,
+ FAR struct nxffs_entry_s *entry)
+{
+ off_t offset;
+ int ret;
+
+ /* Start with the first valid inode that was discovered when the volume
+ * was created (or modified after the last file system re-packing).
+ */
+
+ offset = volume->inoffset;
+
+ /* Loop, checking each NXFFS inode until either: (1) we find the NXFFS inode
+ * with the matching name, or (2) we reach the end of data written on the
+ * media.
+ */
+
+ for (;;)
+ {
+ /* Get the next, valid NXFFS inode entry */
+
+ ret = nxffs_nextentry(volume, offset, entry);
+ if (ret < 0)
+ {
+ fvdbg("No inode found: %d\n", -ret);
+ return ret;
+ }
+
+ /* Is this the NXFFS inode we are looking for? */
+
+ else if (strcmp(name, entry->name) == 0)
+ {
+ /* Yes, return success with the entry data in 'entry' */
+
+ return OK;
+ }
+
+ /* Discard this entry and try the next one. Here we set the
+ * next offset using the raw data length as the offset
+ * increment. This is, of course, not accurate because it
+ * does not account for the data headers that enclose the
+ * data. But it is guaranteed to be less than or equal to
+ * the correct offset and, hence, better then searching
+ * byte-for-byte.
+ */
+
+ offset = nxffs_inodeend(volume, entry);
+ nxffs_freeentry(entry);
+ }
+
+ /* We won't get here, but for some compilers: */
+
+ return -ENOENT;
+}
+
+/****************************************************************************
+ * Name: nxffs_inodeend
+ *
+ * Description:
+ * Return an *approximiate* FLASH offset to end of the inode data. The
+ * returned value is guaranteed to be be less then or equal to the offset
+ * of the thing-of-interest in FLASH. Parsing for interesting things
+ * can begin at that point.
+ *
+ * Assumption: The inode header has been verified by the caller and is
+ * known to contain valid data.
+ *
+ * Input Parameters:
+ * volume - Describes the NXFFS volume
+ * entry - Describes the inode.
+ *
+ * Returned Value:
+ * A FLASH offset to the (approximate) end of the inode data. No errors
+ * are detected.
+ *
+ ****************************************************************************/
+
+off_t nxffs_inodeend(FAR struct nxffs_volume_s *volume,
+ FAR struct nxffs_entry_s *entry)
+{
+ /* A zero length file will have no data blocks */
+
+ if (entry->doffset)
+ {
+ /* This is the maximum size of one data block. It is the physcal size
+ * of the block minus the minimum number of headers: block sna data
+ */
+
+ uint16_t maxsize = volume->geo.blocksize - SIZEOF_NXFFS_BLOCK_HDR - SIZEOF_NXFFS_DATA_HDR;
+
+ /* This is the minimum number of blocks require to span all of the
+ * inode data. One additional block could possibly be required -- we
+ * could make this accurate by looking at the size of the first, perhaps
+ * partial, data block.
+ */
+
+ off_t minblocks = (entry->datlen + maxsize - 1) / maxsize;
+
+ /* And this is our best, simple guess at the end of the inode data */
+
+ return entry->doffset + entry->datlen + minblocks * SIZEOF_NXFFS_DATA_HDR;
+ }
+
+ /* Otherwise, return an offset that accounts only for the inode header and
+ * the inode name.
+ */
+
+ /* All valid inodes will have a name associated with them */
+
+ DEBUGASSERT(entry->noffset);
+ return entry->noffset + strlen(entry->name);
+}
+
+