int nffs_dir_open(const char *path, struct nffs_dir **out_dir) { struct nffs_inode_entry *parent_inode_entry; struct nffs_dir *dir; int rc; rc = nffs_path_find_inode_entry(path, &parent_inode_entry); if (rc != 0) { return rc; } if (!nffs_hash_id_is_dir(parent_inode_entry->nie_hash_entry.nhe_id)) { return FS_EINVAL; } dir = nffs_dir_alloc(); if (dir == NULL) { return FS_ENOMEM; } dir->nd_parent_inode_entry = parent_inode_entry; nffs_inode_inc_refcnt(dir->nd_parent_inode_entry); memset(&dir->nd_dirent, 0, sizeof dir->nd_dirent); *out_dir = dir; return 0; }
int nffs_dir_read(struct nffs_dir *dir, struct nffs_dirent **out_dirent) { struct nffs_inode_entry *child; int rc; if (dir->nd_dirent.nde_inode_entry == NULL) { child = SLIST_FIRST(&dir->nd_parent_inode_entry->nie_child_list); } else { child = SLIST_NEXT(dir->nd_dirent.nde_inode_entry, nie_sibling_next); rc = nffs_inode_dec_refcnt(dir->nd_dirent.nde_inode_entry); if (rc != 0) { /* XXX: Need to clean up anything? */ return rc; } } dir->nd_dirent.nde_inode_entry = child; if (child == NULL) { *out_dirent = NULL; return FS_ENOENT; } nffs_inode_inc_refcnt(child); *out_dirent = &dir->nd_dirent; return 0; }
static int nffs_restore_should_sweep_inode_entry(struct nffs_inode_entry *inode_entry, int *out_should_sweep) { struct nffs_inode inode; int rc; /* * if this inode was tagged to have a dummy block entry and the * flag is still set, that means we didn't find the block and so * should remove this inode and all associated blocks. */ if (nffs_inode_getflags(inode_entry, NFFS_INODE_FLAG_DUMMYLSTBLK)) { *out_should_sweep = 1; /*nffs_inode_inc_refcnt(inode_entry);*/ inode_entry->nie_refcnt = 1; assert(inode_entry->nie_refcnt >= 1); return 0; } /* * This inode was originally created to hold a block that was restored * before the owning inode. If the flag is still set, it means we never * restored the inode from disk and so this entry should be deleted. */ if (nffs_inode_getflags(inode_entry, NFFS_INODE_FLAG_DUMMYINOBLK)) { *out_should_sweep = 2; inode_entry->nie_refcnt = 1; assert(inode_entry->nie_refcnt >= 1); return 0; } /* * Determine if the inode is a dummy. Dummy inodes have a flash * location set to LOC_NONE and should have a flag set for the reason. * The presence of a dummy inode during the final sweep step indicates * file system corruption. It's assumed that directories have * previously migrated all children to /lost+found. */ if (nffs_inode_is_dummy(inode_entry)) { *out_should_sweep = 3; nffs_inode_inc_refcnt(inode_entry); assert(inode_entry->nie_refcnt >= 1); return 0; } /* Determine if the inode has been deleted. If an inode has no parent (and * it isn't the root directory), it has been deleted from the disk and * should be swept from the RAM representation. */ if (inode_entry->nie_hash_entry.nhe_id != NFFS_ID_ROOT_DIR) { rc = nffs_inode_from_entry(&inode, inode_entry); if (rc != 0 && rc != FS_ENOENT) { *out_should_sweep = 0; return rc; } if (inode.ni_parent == NULL) { *out_should_sweep = 4; return 0; } } /* * If this inode has been marked as deleted, we can unlink it here. * * XXX Note that the record of a deletion could be lost if garbage * collection erases the delete but leaves inode updates on other * partitions which can then be restored. */ if (nffs_inode_getflags(inode_entry, NFFS_INODE_FLAG_DELETED)) { rc = nffs_inode_from_entry(&inode, inode_entry); if (rc != 0) { *out_should_sweep = 0; return rc; } *out_should_sweep = 5; } /* If this is a file inode, verify that all of its constituent blocks are * present. */ if (nffs_hash_id_is_file(inode_entry->nie_hash_entry.nhe_id)) { rc = nffs_restore_validate_block_chain( inode_entry->nie_last_block_entry); if (rc == FS_ECORRUPT) { *out_should_sweep = 6; return 0; } else if (rc == FS_ENOENT) { *out_should_sweep = 7; return 0; } else if (rc != 0) { *out_should_sweep = 0; return rc; } } /* This is a valid inode; don't sweep it. */ *out_should_sweep = 0; return 0; }