/** * Constructs a full data block representation from the specified minimal block * entry. The resultant block's pointers are populated via hash table lookups. * * @param out_block On success, this gets populated with the data * block information. * @param block_entry The source block entry to convert. * * @return 0 on success; nonzero on failure. */ int nffs_block_from_hash_entry(struct nffs_block *out_block, struct nffs_hash_entry *block_entry) { struct nffs_disk_block disk_block; uint32_t area_offset; uint8_t area_idx; int rc; assert(nffs_hash_id_is_block(block_entry->nhe_id)); nffs_flash_loc_expand(block_entry->nhe_flash_loc, &area_idx, &area_offset); rc = nffs_block_read_disk(area_idx, area_offset, &disk_block); if (rc != 0) { return rc; } out_block->nb_hash_entry = block_entry; rc = nffs_block_from_disk(out_block, &disk_block, area_idx, area_offset); if (rc != 0) { return rc; } return 0; }
/** * Checks that each block a chain of data blocks was properly restored. * * @param last_block_entry The entry corresponding to the last block in * the chain. * * @return 0 if the block chain is OK; * FS_ECORRUPT if corruption is detected; * nonzero on other error. */ static int nffs_restore_validate_block_chain(struct nffs_hash_entry *last_block_entry) { struct nffs_disk_block disk_block; struct nffs_hash_entry *cur; struct nffs_block block; uint32_t area_offset; uint8_t area_idx; int rc; cur = last_block_entry; while (cur != NULL) { nffs_flash_loc_expand(cur->nhe_flash_loc, &area_idx, &area_offset); rc = nffs_block_read_disk(area_idx, area_offset, &disk_block); if (rc != 0) { return rc; } rc = nffs_block_from_hash_entry(&block, cur); if (rc != 0) { return rc; } cur = block.nb_prev; } return 0; }
/** * Constructs a full data block representation from the specified minimal * block entry. However, the resultant block's pointers are set to null, * rather than populated via hash table lookups. This behavior is useful when * the RAM representation has not been fully constructed yet. * * @param out_block On success, this gets populated with the data * block information. * @param block_entry The source block entry to convert. * * @return 0 on success; nonzero on failure. */ int nffs_block_from_hash_entry_no_ptrs(struct nffs_block *out_block, struct nffs_hash_entry *block_entry) { struct nffs_disk_block disk_block; uint32_t area_offset; uint8_t area_idx; int rc; assert(nffs_hash_id_is_block(block_entry->nhe_id)); if (nffs_hash_entry_is_dummy(block_entry)) { /* * We can't read this from disk so we'll be missing filling in anything * not already in inode_entry (e.g., prev_id). */ out_block->nb_hash_entry = block_entry; return FS_ENOENT; /* let caller know it's a partial inode_entry */ } nffs_flash_loc_expand(block_entry->nhe_flash_loc, &area_idx, &area_offset); rc = nffs_block_read_disk(area_idx, area_offset, &disk_block); if (rc != 0) { return rc; } out_block->nb_hash_entry = block_entry; nffs_block_from_disk_no_ptrs(out_block, &disk_block); return 0; }
/** * Determines if a particular block can be found in RAM by following a chain of * previous block pointers, starting with the specified hash entry. * * @param start The block entry at which to start the search. * @param sought_id The ID of the block to search for. * * @return 0 if the sought after ID was found; * FS_ENOENT if the ID was not found; * Other FS code on error. */ int nffs_block_find_predecessor(struct nffs_hash_entry *start, uint32_t sought_id) { struct nffs_hash_entry *entry; struct nffs_disk_block disk_block; uint32_t area_offset; uint8_t area_idx; int rc; entry = start; while (entry != NULL && entry->nhe_id != sought_id) { nffs_flash_loc_expand(entry->nhe_flash_loc, &area_idx, &area_offset); rc = nffs_block_read_disk(area_idx, area_offset, &disk_block); if (rc != 0) { return rc; } if (disk_block.ndb_prev_id == NFFS_ID_NONE) { entry = NULL; } else { entry = nffs_hash_find(disk_block.ndb_prev_id); } } if (entry == NULL) { rc = FS_ENOENT; } else { rc = 0; } return rc; }
/** * Reads a single disk object from flash. * * @param area_idx The area to read the object from. * @param area_offset The offset within the area to read from. * @param out_disk_object On success, the restored object gets written * here. * * @return 0 on success; nonzero on failure. */ static int nffs_restore_disk_object(int area_idx, uint32_t area_offset, struct nffs_disk_object *out_disk_object) { uint32_t magic; int rc; rc = nffs_flash_read(area_idx, area_offset, &magic, sizeof magic); if (rc != 0) { return rc; } switch (magic) { case NFFS_INODE_MAGIC: out_disk_object->ndo_type = NFFS_OBJECT_TYPE_INODE; rc = nffs_inode_read_disk(area_idx, area_offset, &out_disk_object->ndo_disk_inode); break; case NFFS_BLOCK_MAGIC: out_disk_object->ndo_type = NFFS_OBJECT_TYPE_BLOCK; rc = nffs_block_read_disk(area_idx, area_offset, &out_disk_object->ndo_disk_block); break; case 0xffffffff: rc = FS_EEMPTY; break; default: rc = FS_ECORRUPT; break; } if (rc != 0) { return rc; } out_disk_object->ndo_area_idx = area_idx; out_disk_object->ndo_offset = area_offset; return 0; }
/** * Constructs a block representation from a minimal block hash entry. If the * hash entry references other objects (inode or previous data block), the * resulting block object is populated with pointers to the referenced objects. * If the any referenced objects are not present in the NFFS RAM * representation, this indicates file system corruption. In this case, the * resulting block is populated with all valid references, and an FS_ECORRUPT * code is returned. * * @param out_block On success, this gets populated with the data * block information. * @param block_entry The source block entry to convert. * * @return 0 on success; * FS_ECORRUPT if one or more pointers could not * be filled in due to file system corruption; * FS_EOFFSET on an attempt to read an invalid * address range; * FS_EHW on flash error; * FS_EUNEXP if the specified disk location does * not contain a block. */ int nffs_block_from_hash_entry(struct nffs_block *out_block, struct nffs_hash_entry *block_entry) { struct nffs_disk_block disk_block; uint32_t area_offset; uint8_t area_idx; int rc; assert(nffs_hash_id_is_block(block_entry->nhe_id)); if (nffs_block_is_dummy(block_entry)) { out_block->nb_hash_entry = block_entry; out_block->nb_inode_entry = NULL; out_block->nb_prev = NULL; /* * Dummy block added when inode was read in before real block * (see nffs_restore_inode()). Return success (because there's * too many places that ned to check for this, * but it's the responsibility fo the upstream code to check * whether this is still a dummy entry. XXX */ return 0; /*return FS_ENOENT;*/ } nffs_flash_loc_expand(block_entry->nhe_flash_loc, &area_idx, &area_offset); rc = nffs_block_read_disk(area_idx, area_offset, &disk_block); if (rc != 0) { return rc; } out_block->nb_hash_entry = block_entry; rc = nffs_block_from_disk(out_block, &disk_block); if (rc != 0) { return rc; } return 0; }