예제 #1
0
int nxffs_rdblkhdr(FAR struct nxffs_volume_s *volume, off_t offset,
                   FAR uint16_t *datlen)
{
  struct nxffs_data_s blkhdr;
  uint32_t ecrc;
  uint32_t crc;
  uint16_t doffset;
  uint16_t dlen;
  int ret;

  /* Make sure that the block containing the data block header is in the cache */

  nxffs_ioseek(volume, offset);
  ret = nxffs_rdcache(volume, volume->ioblock);
  if (ret < 0)
    {
      fdbg("ERROR: Failed to read data into cache: %d\n", ret);
      return ret;
    }

  /* Read the header at the FLASH offset */

  doffset = volume->iooffset;
  memcpy(&blkhdr, &volume->cache[doffset], SIZEOF_NXFFS_DATA_HDR);

  /* Extract the data length */

  dlen = nxffs_rdle16(blkhdr.datlen);

  /* Get the offset to the beginning of the data */

  doffset += SIZEOF_NXFFS_DATA_HDR;

  /* Make sure that all of the data fits within the block */

  if ((uint32_t)doffset + (uint32_t)dlen > (uint32_t)volume->geo.blocksize)
    {
      fdbg("ERROR: Data length=%d is unreasonable at offset=%d\n", dlen, doffset);
      return -EIO;
    }

  /* Extract the expected CRC and calculate the CRC of the data block */

  ecrc = nxffs_rdle32(blkhdr.crc);

  nxffs_wrle32(blkhdr.crc, 0);
  crc = crc32((FAR const uint8_t *)&blkhdr, SIZEOF_NXFFS_DATA_HDR);
  crc = crc32part(&volume->cache[doffset], dlen, crc);

  if (crc != ecrc)
    {
      fdbg("ERROR: CRC failure\n");
      return -EIO;
    }

  /* Looks good! Return the data length and success */

  *datlen = dlen;
  return OK;
}
예제 #2
0
static inline int nxffs_wrname(FAR struct nxffs_volume_s *volume,
                               FAR struct nxffs_entry_s *entry,
                               int namlen)
{
  int ret;

  /* Seek to the inode name position and assure that it is in the volume
   * cache.
   */

  nxffs_ioseek(volume, entry->noffset);
  ret = nxffs_rdcache(volume, volume->ioblock);
  if (ret < 0)
    {
      fdbg("ERROR: Failed to read inode name block %d: %d\n",
           volume->ioblock, -ret);
      return ret;
    }

  /* Copy the inode name to the volume cache and write the inode name block */

  memcpy(&volume->cache[volume->iooffset], entry->name, namlen);
  ret = nxffs_wrcache(volume);
  if (ret < 0)
    {
      fdbg("ERROR: Failed to write inode header block %d: %d\n",
           volume->ioblock, -ret);
    }

  return ret;
}
예제 #3
0
static ssize_t nxffs_rdseek(FAR struct nxffs_volume_s *volume,
                            FAR struct nxffs_entry_s *entry,
                            off_t fpos,
                            FAR struct nxffs_blkentry_s *blkentry)
{
  size_t datstart;
  size_t datend;
  off_t offset;
  int ret;

  /* The initial FLASH offset will be the offset to first data block of
   * the inode
   */

  offset = entry->doffset;
  if (offset == 0)
    {
      /* Zero length files will have no data blocks */

      return -ENOSPC;
    }

  /* Loop until we read the data block containing the desired position */

  datend = 0;
  do
    {
      /* Check if the next data block contains the sought after file position */

      ret = nxffs_nextblock(volume, offset, blkentry);
      if (ret < 0)
        {
          fdbg("ERROR: nxffs_nextblock failed: %d\n", -ret);
          return ret;
        }

      /* Get the range of data offsets for this data block */

      datstart  = datend;
      datend   += blkentry->datlen;

      /* Offset to search for the next data block */

      offset = blkentry->hoffset + SIZEOF_NXFFS_DATA_HDR + blkentry->datlen;
    }
  while (datend <= fpos);

  /* Return the offset to the data within the current data block */

  blkentry->foffset = fpos - datstart;
  nxffs_ioseek(volume, blkentry->hoffset + SIZEOF_NXFFS_DATA_HDR + blkentry->foffset);
  return OK;
}
예제 #4
0
int nxffs_wrinode(FAR struct nxffs_volume_s *volume,
                  FAR struct nxffs_entry_s *entry)
{
  FAR struct nxffs_inode_s *inode;
  uint32_t crc;
  int namlen;
  int ret;

  /* Seek to the inode header position and assure that it is in the volume
   * cache.
   */

  nxffs_ioseek(volume, entry->hoffset);
  ret = nxffs_rdcache(volume, volume->ioblock);
  if (ret < 0)
    {
      fdbg("ERROR: Failed to read inode header block %d: %d\n",
           volume->ioblock, -ret);
      goto errout;
    }

  /* Get the length of the inode name */

  namlen = strlen(entry->name);
  DEBUGASSERT(namlen < CONFIG_NXFFS_MAXNAMLEN); /* This was verified earlier */

  /* Initialize the inode header */

  inode = (FAR struct nxffs_inode_s *)&volume->cache[volume->iooffset];
  memcpy(inode->magic, g_inodemagic, NXFFS_MAGICSIZE);

  inode->state  = CONFIG_NXFFS_ERASEDSTATE;
  inode->namlen = namlen;

  nxffs_wrle32(inode->noffs,  entry->noffset);
  nxffs_wrle32(inode->doffs,  entry->doffset);
  nxffs_wrle32(inode->utc,    entry->utc);
  nxffs_wrle32(inode->crc,    0);
  nxffs_wrle32(inode->datlen, entry->datlen);

  /* Calculate the CRC */

  crc = crc32((FAR const uint8_t *)inode, SIZEOF_NXFFS_INODE_HDR);
  crc = crc32part((FAR const uint8_t *)entry->name, namlen, crc);

  /* Finish the inode header */

  inode->state = INODE_STATE_FILE;
  nxffs_wrle32(inode->crc, crc);

  /* Write the block with the inode header */

  ret = nxffs_wrcache(volume);
  if (ret < 0)
    {
      fdbg("ERROR: Failed to write inode header block %d: %d\n",
           volume->ioblock, -ret);
    }

  /* The volume is now available for other writers */

errout:
  sem_post(&volume->wrsem);
  return ret;
}
예제 #5
0
int nxffs_rminode(FAR struct nxffs_volume_s *volume, FAR const char *name)
{
  FAR struct nxffs_ofile_s *ofile;
  FAR struct nxffs_inode_s *inode;
  struct nxffs_entry_s entry;
  int ret;

  /* Check if the file is open */

  ofile = nxffs_findofile(volume, name);
  if (ofile)
    {
      /* We can't remove the inode if it is open */

      fdbg("Inode '%s' is open\n", name);
      ret = -EBUSY;
      goto errout;
    }

  /* Find the NXFFS inode */

  ret = nxffs_findinode(volume, name, &entry);
  if (ret < 0)
    {
      fdbg("Inode '%s' not found\n", name);
      goto errout;
    }

  /* Set the position to the FLASH offset of the file header (nxffs_findinode
   * should have left the block in the cache).
   */

  nxffs_ioseek(volume, entry.hoffset);

  /* Make sure that the block is in the cache */

  ret = nxffs_rdcache(volume, volume->ioblock);
  if (ret < 0)
    {
      fdbg("Failed to read data into cache: %d\n", ret);
      goto errout_with_entry;
    }

  /* Change the file status... it is no longer valid */

  inode = (FAR struct nxffs_inode_s *)&volume->cache[volume->iooffset];
  inode->state = INODE_STATE_DELETED;

  /* Then write the cached block back to FLASH */

  ret = nxffs_wrcache(volume);
  if (ret < 0)
    {
      fdbg("Failed to read data into cache: %d\n", ret);
    }

errout_with_entry:
  nxffs_freeentry(&entry);
errout:
  return ret;
}
예제 #6
0
int nxffs_nextblock(FAR struct nxffs_volume_s *volume, off_t offset,
                    FAR struct nxffs_blkentry_s *blkentry)
{
  int nmagic;
  int ch;
  int nerased;
  int ret;

  /* Seek to the first FLASH offset provided by the caller. */

  nxffs_ioseek(volume, offset);

  /* Skip the block header */

  if (volume->iooffset < SIZEOF_NXFFS_BLOCK_HDR)
    {
      volume->iooffset = SIZEOF_NXFFS_BLOCK_HDR;
    }

  /* Then begin searching */

  nerased = 0;
  nmagic  = 0;

  for (;;)
    {
      /* Read the next character */

      ch = nxffs_getc(volume, SIZEOF_NXFFS_DATA_HDR - nmagic);
      if (ch < 0)
        {
          fdbg("ERROR: 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
           * data block or start of the next inode. There is the possibility
           * of this magic sequnce occurring in FLASH data.  However, the
           * data block CRC should distinguish between real NXFFS data blocks
           * headers and such false alarms.
           */

          if (ch != g_datamagic[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_datamagic[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 data block.
           */

          else
            {
              /* The offset to the header must be 4 bytes before the current
               * FLASH seek location.
               */

              blkentry->hoffset = nxffs_iotell(volume) - NXFFS_MAGICSIZE;

              /* Read the block header and verify the block at that address */

              ret = nxffs_rdblkhdr(volume, blkentry->hoffset, &blkentry->datlen);
              if (ret == OK)
                {
                  fvdbg("Found a valid data block, offset: %d datlen: %d\n",
                        blkentry->hoffset, blkentry->datlen);
                  return OK;
                }

              /* False alarm.. Restore the volume cache position (that was
               * destroyed by nxfs_rdblkhdr()) and keep looking.
               */

              nxffs_ioseek(volume, blkentry->hoffset + NXFFS_MAGICSIZE);
              nmagic = 0;
            }
        }
    }

  /* We won't get here, but to keep some compilers happy: */

  return -ENOENT;
}
int nxffs_wrblkhdr(FAR struct nxffs_volume_s *volume,
                   FAR struct nxffs_wrfile_s *wrfile)
{
  FAR struct nxffs_data_s *dathdr;
  int ret;

  /* Write the data block header to memory */

  nxffs_ioseek(volume, wrfile->doffset);
  dathdr = (FAR struct nxffs_data_s *)&volume->cache[volume->iooffset];
  memcpy(dathdr->magic, g_datamagic, NXFFS_MAGICSIZE);
  nxffs_wrle32(dathdr->crc, 0);
  nxffs_wrle16(dathdr->datlen, wrfile->datlen);

  /* Update the entire data block CRC (including the header) */

  wrfile->crc = crc32(&volume->cache[volume->iooffset], wrfile->datlen + SIZEOF_NXFFS_DATA_HDR);
  nxffs_wrle32(dathdr->crc, wrfile->crc);

  /* And write the data block to FLASH */

  ret = nxffs_wrcache(volume);
  if (ret < 0)
    {
      fdbg("ERROR: nxffs_wrcache failed: %d\n", -ret);
      goto errout;
    }

  /* After the block has been successfully written to flash, update the inode
   * statistics and reset the write state.
   *
   * volume:
   *   froffset - The offset the next free FLASH region.  Set to just after
   *     the inode data block that we just wrote.  This is where we will
   *     begin the search for the next inode header or data block.
   */

  volume->froffset = (wrfile->doffset + wrfile->datlen + SIZEOF_NXFFS_DATA_HDR);

  /* wrfile->file.entry:
   *   datlen:  Total file length accumulated so far.  When the file is
   *     closed, this will hold the file length.
   *   doffset: Offset to the first data block.  Only the offset to the
   *     first data block is saved.
   */

  wrfile->ofile.entry.datlen += wrfile->datlen;
  if (wrfile->ofile.entry.doffset == 0)
    {
      wrfile->ofile.entry.doffset = wrfile->doffset;
    }

  /* Return success */

  ret = OK;

errout:
  wrfile->crc     = 0;
  wrfile->doffset = 0;
  wrfile->datlen  = 0;
  return ret;
}
예제 #8
0
int nxffs_limits(FAR struct nxffs_volume_s *volume)
{
  FAR struct nxffs_entry_s entry;
  off_t block;
  off_t offset;
  bool noinodes = false;
  int nerased;
  int ret;

  /* Get the offset to the first valid block on the FLASH */

  block = 0;
  ret = nxffs_validblock(volume, &block);
  if (ret < 0)
    {
      fdbg("Failed to find a valid block: %d\n", -ret);
      return ret;
    }

  /* Then find the first valid inode in or beyond the first valid block */

  offset = block * volume->geo.blocksize;
  ret = nxffs_nextentry(volume, offset, &entry);
  if (ret < 0)
    {
      /* The value -ENOENT is special.  This simply means that the FLASH
       * was searched to the end and no valid inode was found... the file
       * system is empty (or, in more perverse cases, all inodes are
       * deleted or corrupted).
       */

      if (ret != -ENOENT)
        {
          fdbg("nxffs_nextentry failed: %d\n", -ret);
          return ret;
        }

      /* Set a flag the just indicates that no inodes were found.  Later,
       * we will set the location of the first inode to be the same as
       * the location of the free FLASH region.
       */

      fvdbg("No inodes found\n");
      noinodes = true;
    }
  else
    {
      /* Save the offset to the first inode */

      volume->inoffset = entry.hoffset;
      fvdbg("First inode at offset %d\n", volume->inoffset);

      /* Discard this entry and set the next offset. */

      offset = nxffs_inodeend(volume, &entry);
      nxffs_freeentry(&entry);
    }

  /* Now, search for the last valid entry */

  if (!noinodes)
    {
      while ((ret = nxffs_nextentry(volume, offset, &entry)) == OK)
        {
          /* Discard the entry and guess the next offset. */

          offset = nxffs_inodeend(volume, &entry);
          nxffs_freeentry(&entry);    
        }
      fvdbg("Last inode before offset %d\n", offset);
    }

  /* No inodes were found after this offset.  Now search for a block of
   * erased flash.
   */

  nxffs_ioseek(volume, offset);
  nerased = 0;
  for (;;)
    {
      int ch = nxffs_getc(volume, 1);
      if (ch < 0)
        {
          /* Failed to read the next byte... this could mean that the FLASH
           * is full?
           */

          if (volume->ioblock + 1 >= volume->nblocks &&
              volume->iooffset + 1 >= volume->geo.blocksize)
            {
              /* Yes.. the FLASH is full.  Force the offsets to the end of FLASH */

              volume->froffset = volume->nblocks * volume->geo.blocksize;
              fvdbg("Assume no free FLASH, froffset: %d\n", volume->froffset);
              if (noinodes)
                {
                  volume->inoffset = volume->froffset;
                  fvdbg("No inodes, inoffset: %d\n", volume->inoffset);
                }
              return OK;
            }

          // No?  Then it is some other failure that we do not know how to handle

          fdbg("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)
            {
              /* Okay.. we have a long stretch of erased FLASH in a valid
               * FLASH block.  Let's say that this is the beginning of
               * the free FLASH region.
               */

              volume->froffset = offset;
              fvdbg("Free FLASH region begins at offset: %d\n", volume->froffset);
              if (noinodes)
                {
                  volume->inoffset = offset;
                  fvdbg("First inode at offset %d\n", volume->inoffset);
                }
              return OK;
            }
        }
      else
        {
          offset += nerased + 1;
          nerased = 0;
        }
    }

  /* Won't get here */

  return OK;
}
int nxffs_wrreserve(FAR struct nxffs_volume_s *volume, size_t size)
{
  int ret;

  /* Seek to the beginning of the free FLASH region */

  nxffs_ioseek(volume, volume->froffset);

  /* Check for a seek past the end of the volume */

  if (volume->ioblock >= volume->nblocks)
    {
      /* Return -ENOSPC to indicate that the volume is full */

      return -ENOSPC;
    }

  /* Skip over block headers */

  if (volume->iooffset < SIZEOF_NXFFS_BLOCK_HDR)
    {
      volume->iooffset = SIZEOF_NXFFS_BLOCK_HDR;
    }

  /* Make sure that there is space there to hold the entire object */

  if (volume->iooffset + size > volume->geo.blocksize)
    {
      /* We will need to skip to the next block.  But first, check if we are
       * already at the final block.
       */

      if (volume->ioblock + 1 >= volume->nblocks)
        {
          /* Return -ENOSPC to indicate that the volume is full */

          fdbg("ERROR: No space in last block\n");
          return -ENOSPC;
        }

      /* This is not the last block in the volume, so just seek to the
       * beginning of the next, valid block.
       */

      volume->ioblock++;
      ret = nxffs_validblock(volume, &volume->ioblock);
      if (ret < 0)
        {
          fdbg("ERROR: No more valid blocks\n");
          return ret;
        }

      volume->iooffset = SIZEOF_NXFFS_BLOCK_HDR;
    }

  /* Update the pointer to the first next free FLASH memory -- reserving this
   * block of memory.
   */

  volume->froffset = nxffs_iotell(volume) + size;
  return OK;
}
ssize_t nxffs_write(FAR struct file *filep, FAR const char *buffer, size_t buflen)
{
  FAR struct nxffs_volume_s *volume;
  FAR struct nxffs_wrfile_s *wrfile;
  ssize_t remaining;
  ssize_t nwritten;
  ssize_t total;
  int ret;

  fvdbg("Write %d bytes to offset %d\n", buflen, filep->f_pos);

  /* Sanity checks */

  DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);

  /* Recover the open file state from the struct file instance */

  wrfile = (FAR struct nxffs_wrfile_s *)filep->f_priv;

  /* Recover the volume state from the open file */

  volume = (FAR struct nxffs_volume_s *)filep->f_inode->i_private;
  DEBUGASSERT(volume != NULL);

  /* Get exclusive access to the volume.  Note that the volume exclsem
   * protects the open file list.
   */

  ret = sem_wait(&volume->exclsem);
  if (ret != OK)
    {
      ret = -errno;
      fdbg("ERROR: sem_wait failed: %d\n", ret);
      goto errout;
    }

  /* Check if the file was opened with write access */

  if ((wrfile->ofile.oflags & O_WROK) == 0)
    {
      fdbg("ERROR: File not open for write access\n");
      ret = -EACCES;
      goto errout_with_semaphore;
    }

  /* Loop until we successfully appended all of the data to the file (or an
   * error occurs)
   */

  for (total = 0; total < buflen; )
    {
      remaining = buflen - total;

      /* Have we already allocated the data block? */

      if (wrfile->doffset == 0)
        {
          /* No, allocate the data block now, re-packing if necessary. */

          wrfile->datlen = 0;
          ret = nxffs_wralloc(volume, wrfile, remaining);
          if (ret < 0)
            {
              fdbg("ERROR: Failed to allocate a data block: %d\n", -ret);
              goto errout_with_semaphore;
            }
        }

      /* Seek to the FLASH block containing the data block */

      nxffs_ioseek(volume, wrfile->doffset);

      /* Verify that the FLASH data that was previously written is still intact */

      ret = nxffs_reverify(volume, wrfile);
      if (ret < 0)
        {
          fdbg("ERROR: Failed to verify FLASH data block: %d\n", -ret);
          goto errout_with_semaphore;
        }

      /* Append the data to the end of the data block and write the updated
       * block to flash.
       */

      nwritten = nxffs_wrappend(volume, wrfile, &buffer[total], remaining);
      if (nwritten < 0)
        {
          fdbg("ERROR: Failed to append to FLASH to a data block: %d\n", -ret);
          goto errout_with_semaphore;
        }

      /* Decrement the number of bytes remaining to be written */

      total += nwritten;
    }

  /* Success.. return the number of bytes written */

  ret           = total;
  filep->f_pos  = wrfile->datlen;

errout_with_semaphore:
  sem_post(&volume->exclsem);
errout:
  return ret;
}
static inline int nxffs_wralloc(FAR struct nxffs_volume_s *volume,
                                FAR struct nxffs_wrfile_s *wrfile,
                                size_t size)
{
  bool packed;
  int ret;

  /* Allocate FLASH memory for the data block.
   *
   * Loop until the data block header is configured or until a failure
   * occurs. Note that nothing is written to FLASH.  The data block header
   * is not written until either (1) the file is closed, or (2) the data
   * region is fully populated.
   */

  packed = false;
  for (;;)
    {
      size_t mindata = MIN(NXFFS_MINDATA, size);

      /* File a valid location to position the data block.  Start with
       * the first byte in the free FLASH region.
       */

      ret = nxffs_hdrpos(volume, wrfile, mindata);
      if (ret == OK)
        {
          /* Find a region of memory in the block that is fully erased */

          ret = nxffs_hdrerased(volume, wrfile, mindata);
          if (ret == OK)
            {
              /* Valid memory for the data block was found.  Return success. */

              return OK;
            }
        }

      /* If no valid memory is found searching to the end of the volume,
       * then -ENOSPC will be returned.  Other errors are not handled.
       */

      if (ret != -ENOSPC || packed)
        {
          fdbg("ERROR: Failed to find inode header memory: %d\n", -ret);
          return -ENOSPC;
        }

      /* -ENOSPC is a special case..  It means that the volume is full.
       * Try to pack the volume in order to free up some space.
       */

      ret = nxffs_pack(volume);
      if (ret < 0)
        {
          fdbg("ERROR: Failed to pack the volume: %d\n", -ret);
          return ret;
        }

      /* After packing the volume, froffset will be updated to point to the
       * new free flash region.  Try again.
       */

      nxffs_ioseek(volume, volume->froffset);
      packed = true;
    }

  /* Can't get here */

  return OK;
}
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("ERROR: 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("ERROR: 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("ERROR: 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;
}
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)
        {
          fdbg("ERROR: 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;
}