static inline int nxffs_wrname(FAR struct nxffs_volume_s *volume, FAR struct nxffs_entry_s *entry, int namlen) { int ret; /* Seek to the inode name position and assure that it is in the volume * cache. */ nxffs_ioseek(volume, entry->noffset); ret = nxffs_rdcache(volume, volume->ioblock); if (ret < 0) { fdbg("ERROR: Failed to read inode name block %d: %d\n", volume->ioblock, -ret); return ret; } /* Copy the inode name to the volume cache and write the inode name block */ memcpy(&volume->cache[volume->iooffset], entry->name, namlen); ret = nxffs_wrcache(volume); if (ret < 0) { fdbg("ERROR: Failed to write inode header block %d: %d\n", volume->ioblock, -ret); } return ret; }
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; }
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; }
int nxffs_rminode(FAR struct nxffs_volume_s *volume, FAR const char *name) { FAR struct nxffs_ofile_s *ofile; FAR struct nxffs_inode_s *inode; struct nxffs_entry_s entry; int ret; /* Check if the file is open */ ofile = nxffs_findofile(volume, name); if (ofile) { /* We can't remove the inode if it is open */ fdbg("Inode '%s' is open\n", name); ret = -EBUSY; goto errout; } /* Find the NXFFS inode */ ret = nxffs_findinode(volume, name, &entry); if (ret < 0) { fdbg("Inode '%s' not found\n", name); goto errout; } /* Set the position to the FLASH offset of the file header (nxffs_findinode * should have left the block in the cache). */ nxffs_ioseek(volume, entry.hoffset); /* Make sure that the block is in the cache */ ret = nxffs_rdcache(volume, volume->ioblock); if (ret < 0) { fdbg("Failed to read data into cache: %d\n", ret); goto errout_with_entry; } /* Change the file status... it is no longer valid */ inode = (FAR struct nxffs_inode_s *)&volume->cache[volume->iooffset]; inode->state = INODE_STATE_DELETED; /* Then write the cached block back to FLASH */ ret = nxffs_wrcache(volume); if (ret < 0) { fdbg("Failed to read data into cache: %d\n", ret); } errout_with_entry: nxffs_freeentry(&entry); errout: return ret; }
int nxffs_wrverify(FAR struct nxffs_volume_s *volume, size_t size) { uint16_t iooffset; int nerased; int ret; int i; /* Search to the very last block in the volume if we have to */ while (volume->ioblock < volume->nblocks) { /* Make sure that the block is in memory */ ret = nxffs_rdcache(volume, volume->ioblock); if (ret < 0) { /* Ignore the error... just skip to the next block. This should * never happen with normal FLASH, but could occur with NAND if * the block has uncorrectable bit errors. */ fdbg("ERROR: Failed to read block %d: %d\n", volume->ioblock, -ret); } /* Search to the very end of this block if we have to */ else { iooffset = volume->iooffset; nerased = 0; for (i = volume->iooffset; i < volume->geo.blocksize; i++) { /* Is this byte erased? */ if (volume->cache[i] == CONFIG_NXFFS_ERASEDSTATE) { /* Yes.. increment the count of contiguous, erased bytes */ nerased++; /* Is the whole header memory erased? */ if (nerased >= size) { /* Yes.. this this is where we will put the object */ off_t offset = volume->ioblock * volume->geo.blocksize + iooffset; /* Update the free flash offset and return success */ volume->froffset = offset + size; return OK; } } /* This byte is not erased! (It should be unless the block is * bad) */ else { nerased = 0; iooffset = i + 1; } } } /* If we get here, then either (1) this block is not read-able, or * (2) we have looked at every byte in the block and did not find * any sequence of erased bytes long enough to hold the object. * Skip to the next, valid block. */ volume->ioblock++; ret = nxffs_validblock(volume, &volume->ioblock); if (ret < 0) { fdbg("ERROR: No more valid blocks\n"); return ret; } volume->iooffset = SIZEOF_NXFFS_BLOCK_HDR; volume->froffset = volume->ioblock * volume->geo.blocksize + SIZEOF_NXFFS_BLOCK_HDR; } /* Return -ENOSPC if there is no erased memory left in the volume for * the object. */ fdbg("ERROR: Not enough memory left to hold the file header\n"); return -ENOSPC; }
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; }