static int nxffs_badblocks(FAR struct nxffs_volume_s *volume) { FAR uint8_t *blkptr; /* Pointer to next block data */ off_t eblock; /* Erase block number */ off_t lblock; /* Logical block number */ ssize_t nxfrd; /* Number of blocks transferred */ bool good; /* TRUE: block is good */ bool modified; /* TRUE: The erase block has been modified */ int i; /* Read and verify each erase block */ for (eblock = 0; eblock < volume->geo.neraseblocks; eblock++) { /* Read the entire erase block */ lblock = eblock * volume->blkper; nxfrd = MTD_BREAD(volume->mtd, lblock, volume->blkper, volume->pack); if (nxfrd != volume->blkper) { fdbg("Read erase block %d failed: %d\n", lblock, nxfrd); return -EIO; } /* Process each logical block */ modified = false; for (blkptr = volume->pack, i = 0; i < volume->blkper; blkptr += volume->geo.blocksize, i++) { FAR struct nxffs_block_s *blkhdr = (FAR struct nxffs_block_s*)blkptr; /* Check block header */ good = true; if (memcmp(blkhdr->magic, g_blockmagic, NXFFS_MAGICSIZE) != 0 || blkhdr->state != BLOCK_STATE_GOOD) { good = false; } /* Check that block data is erased */ else { size_t blocksize = volume->geo.blocksize - SIZEOF_NXFFS_BLOCK_HDR; size_t erasesize = nxffs_erased(&blkptr[SIZEOF_NXFFS_BLOCK_HDR], blocksize); good = (blocksize == erasesize); } /* If the block is bad, attempt to re-write the block header indicating * a bad block (of course, if the block has failed, this may not be * possible, depending upon failure modes. */ if (!good) { memcpy(blkhdr->magic, g_blockmagic, NXFFS_MAGICSIZE); blkhdr->state = BLOCK_STATE_BAD; modified = true; } } /* If the erase block was modified, then re-write it */ if (modified) { nxfrd = MTD_BWRITE(volume->mtd, lblock, volume->blkper, volume->pack); if (nxfrd != volume->blkper) { fdbg("Write erase block %d failed: %d\n", lblock, nxfrd); return -EIO; } } } return OK; }
static inline void nxffs_analyze(FAR struct nxffs_blkinfo_s *blkinfo) { FAR struct nxffs_block_s *blkhdr; ssize_t nbytes; int hdrndx; int datndx; int inndx; int i; /* Verify that there is a header on the block */ blkhdr = (FAR struct nxffs_block_s *)blkinfo->buffer; if (memcmp(blkhdr->magic, g_blockmagic, NXFFS_MAGICSIZE) != 0) { fdbg(g_format, blkinfo->block, 0, "BLOCK", "NO FRMT", blkinfo->geo.blocksize); } else if (blkhdr->state == BLOCK_STATE_GOOD) { size_t datsize = blkinfo->geo.blocksize - SIZEOF_NXFFS_BLOCK_HDR; size_t nerased = nxffs_erased(blkinfo->buffer + SIZEOF_NXFFS_BLOCK_HDR, datsize); if (nerased == datsize) { if (blkinfo->verbose) { fdbg(g_format, blkinfo->block, 0, "BLOCK", "ERASED ", blkinfo->geo.blocksize); } return; } #if 0 /* Too much output, to little information */ else { fdbg(g_format, blkinfo->block, 0, "BLOCK", "IN USE ", blkinfo->geo.blocksize); } #endif } else if (blkhdr->state == BLOCK_STATE_BAD) { fdbg(g_format, blkinfo->block, 0, "BLOCK", "BAD ", blkinfo->geo.blocksize); } else { fdbg(g_format, blkinfo->block, 0, "BLOCK", "CORRUPT", blkinfo->geo.blocksize); } /* Serach for Inode and data block headers. */ inndx = 0; datndx = 0; for (i = SIZEOF_NXFFS_BLOCK_HDR; i < blkinfo->geo.blocksize; i++) { uint8_t ch = blkinfo->buffer[i]; if (ch == g_inodemagic[inndx]) { inndx++; datndx = 0; if (inndx == NXFFS_MAGICSIZE) { hdrndx = i - NXFFS_MAGICSIZE + 1; nbytes = nxffs_analyzeinode(blkinfo, hdrndx); if (nbytes > 0) { i = hdrndx + nbytes - 1; } inndx = 0; } } else if (ch == g_datamagic[datndx]) { datndx++; inndx = 0; if (datndx == NXFFS_MAGICSIZE) { hdrndx = i - NXFFS_MAGICSIZE + 1; nbytes = nxffs_analyzedata(blkinfo, hdrndx); if (nbytes > 0) { i = hdrndx + nbytes - 1; } datndx = 0; } } } }
static inline ssize_t nxffs_wrappend(FAR struct nxffs_volume_s *volume, FAR struct nxffs_wrfile_s *wrfile, FAR const char *buffer, size_t buflen) { ssize_t maxsize; size_t nbytestowrite; ssize_t nbytesleft; off_t offset; int ret; /* Get the offset to the start of unwritten data */ offset = volume->iooffset + wrfile->datlen + SIZEOF_NXFFS_DATA_HDR; /* Determine that maximum amount of data that can be written to this * block. */ maxsize = volume->geo.blocksize - offset; DEBUGASSERT(maxsize > 0); /* But don't try to write over any unerased bytes */ maxsize = nxffs_erased(&volume->cache[offset], maxsize); /* Write as many bytes as we can into the data buffer */ nbytestowrite = MIN(maxsize, buflen); nbytesleft = maxsize - nbytestowrite; if (nbytestowrite > 0) { /* Copy the data into the volume write cache */ memcpy(&volume->cache[offset], buffer, nbytestowrite); /* Increment the number of bytes written to the data block */ wrfile->datlen += nbytestowrite; /* Re-calculate the CRC */ offset = volume->iooffset + SIZEOF_NXFFS_DATA_HDR; wrfile->crc = crc32(&volume->cache[offset], wrfile->datlen); /* And write the partial write block to FLASH -- unless the data * block is full. In that case, the block will be written below. */ if (nbytesleft > 0) { ret = nxffs_wrcache(volume); if (ret < 0) { fdbg("ERROR: nxffs_wrcache failed: %d\n", -ret); return ret; } } } /* Check if the data block is now full */ if (nbytesleft <= 0) { /* The data block is full, write the block to FLASH */ ret = nxffs_wrblkhdr(volume, wrfile); if (ret < 0) { fdbg("ERROR: nxffs_wrblkdhr failed: %d\n", -ret); return ret; } } /* Return the number of bytes written to FLASH this time */ return nbytestowrite; }