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;
}
示例#2
0
int nxffs_readdir(FAR struct inode *mountpt, FAR struct fs_dirent_s *dir)
{
  FAR struct nxffs_volume_s *volume;
  FAR struct nxffs_entry_s entry;
  off_t offset;
  int ret;

  /* Sanity checks */

  DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL);

  /* Recover the file system state from the NuttX inode instance */

  volume = mountpt->i_private;
  ret = sem_wait(&volume->exclsem);
  if (ret != OK)
    {
      goto errout;
    }

  /* Read the next inode header from the offset */

  offset = dir->u.nxffs.nx_offset;
  ret = nxffs_nextentry(volume, offset, &entry);

  /* If the read was successful, then handle the reported inode.  Note
   * that when the last inode has been reported, the value -ENOENT will
   * be returned.. which is correct for the readdir() method.
   */

  if (ret == OK)
    {
      /* Return the filename and file type */

      fvdbg("Offset %d: \"%s\"\n", entry.hoffset, entry.name);
      dir->fd_dir.d_type = DTYPE_FILE;
      strncpy(dir->fd_dir.d_name, entry.name, NAME_MAX+1);

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

      dir->u.nxffs.nx_offset = nxffs_inodeend(volume, &entry);
      nxffs_freeentry(&entry);
      ret = OK;
    }

  sem_post(&volume->exclsem);
errout:
  return ret;
}
示例#3
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;
}
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;
}