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