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; }
static inline ssize_t nxffs_analyzedata(FAR struct nxffs_blkinfo_s *blkinfo, int offset) { struct nxffs_data_s dathdr; uint32_t ecrc; uint16_t datlen; uint32_t crc; /* Copy and unpack the data block header */ memcpy(&dathdr, &blkinfo->buffer[offset], SIZEOF_NXFFS_DATA_HDR); ecrc = nxffs_rdle32(dathdr.crc); datlen = nxffs_rdle16(dathdr.datlen); /* Sanity checks */ if (offset + SIZEOF_NXFFS_DATA_HDR + datlen > blkinfo->geo.blocksize) { /* Data does not fit in within the block, this can't be a data block */ return ERROR; } /* Calculate the CRC */ nxffs_wrle32(dathdr.crc, 0); crc = crc32((FAR const uint8_t *)&dathdr, SIZEOF_NXFFS_DATA_HDR); crc = crc32part(&blkinfo->buffer[offset + SIZEOF_NXFFS_DATA_HDR], datlen, crc); if (crc != ecrc) { syslog(LOG_NOTICE, g_format, blkinfo->block, offset, "DATA ", "CRC BAD", datlen); return ERROR; } /* If must be a good header */ if (blkinfo->verbose) { syslog(LOG_NOTICE, g_format, blkinfo->block, offset, "DATA ", "OK ", datlen); } return SIZEOF_NXFFS_DATA_HDR + datlen; }
static inline ssize_t nxffs_analyzeinode(FAR struct nxffs_blkinfo_s *blkinfo, int offset) { FAR struct nxffs_inode_s inode; off_t nextblock; uint8_t state; uint32_t noffs; uint32_t doffs; uint32_t utc; uint32_t ecrc; uint32_t datlen; uint32_t crc; size_t spaceleft; /* Verify that there is space for an inode header remaining in the block */ if (offset + SIZEOF_NXFFS_INODE_HDR > blkinfo->geo.blocksize) { /* No.. then this can't be an inode header */ return ERROR; } /* Unpack the header */ memcpy(&inode, &blkinfo->buffer[offset], SIZEOF_NXFFS_INODE_HDR); noffs = nxffs_rdle32(inode.noffs); doffs = nxffs_rdle32(inode.doffs); utc = nxffs_rdle32(inode.utc); ecrc = nxffs_rdle32(inode.crc); datlen = nxffs_rdle32(inode.datlen); /* Misc. sanity checks */ if (noffs < blkinfo->offset + offset + SIZEOF_NXFFS_BLOCK_HDR) { /* The name begins before the inode header. This can't can't be * a real inode header (or it is a corrupted one). */ return ERROR; } /* Can we verify the inode? We need to have the inode name in the same * block to do that (or get access to the next block) */ if (doffs < blkinfo->offset + offset + SIZEOF_NXFFS_BLOCK_HDR) { /* The first data block begins before the inode header. This can't can't * be a real inode header (or it is a corrupted one). */ return ERROR; } spaceleft = (blkinfo->nblocks - blkinfo->block) * blkinfo->geo.blocksize; spaceleft -= (offset + SIZEOF_NXFFS_BLOCK_HDR); if (datlen > spaceleft) { /* The data length is greater than what would fit in the rest of FLASH * (even ignoring block and data header sizes. */ return ERROR; } /* The name begins after the inode header. Does it begin in this block? */ nextblock = blkinfo->offset + blkinfo->geo.blocksize; if (noffs > nextblock) { /* Not than we cannot verify the inode header */ if (blkinfo->verbose) { fdbg(g_format, blkinfo->block, offset, "INODE", "UNVERFD", datlen); } return ERROR; } /* The name begins in this block. Does it also end in this block? */ if (noffs + inode.namlen > nextblock) { /* No.. Assume that this is not an inode. */ return ERROR; } /* Calculate the CRC */ state = inode.state; inode.state = CONFIG_NXFFS_ERASEDSTATE; nxffs_wrle32(inode.crc, 0); crc = crc32((FAR const uint8_t *)&inode, SIZEOF_NXFFS_INODE_HDR); crc = crc32part(&blkinfo->buffer[noffs - blkinfo->offset], inode.namlen, crc); if (crc != ecrc) { fdbg(g_format, blkinfo->block, offset, "INODE", "CRC BAD", datlen); return ERROR; } /* If must be a good header */ if (state == INODE_STATE_FILE) { if (blkinfo->verbose) { fdbg(g_format, blkinfo->block, offset, "INODE", "OK ", datlen); } } else if (state == INODE_STATE_DELETED) { if (blkinfo->verbose) { fdbg(g_format, blkinfo->block, offset, "INODE", "DELETED", datlen); } } else { fdbg(g_format, blkinfo->block, offset, "INODE", "CORRUPT", datlen); } /* Return the block-relative offset to the next byte after the inode name */ return noffs + inode.namlen - offset - blkinfo->offset; }
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; }