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; }
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; }
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; }