static void _InsertToEntry(uffs_Device *dev, u16 *entry, int hash, TreeNode *node) { node->hash_next = entry[hash]; node->hash_prev = EMPTY_NODE; if (entry[hash] != EMPTY_NODE) { FROM_IDX(entry[hash], TPOOL(dev))->hash_prev = TO_IDX(node, TPOOL(dev)); } entry[hash] = TO_IDX(node, TPOOL(dev)); }
TreeNode * uffs_TreeFindDirNodeByName(uffs_Device *dev, const char *name, u32 len, u16 sum, u16 parent) { int i; u16 x; TreeNode *node; struct uffs_TreeSt *tree = &(dev->tree); for (i = 0; i < DIR_NODE_ENTRY_LEN; i++) { x = tree->dir_entry[i]; while (x != EMPTY_NODE) { node = FROM_IDX(x, TPOOL(dev)); if (node->u.dir.checksum == sum && node->u.dir.parent == parent) { //read file name from flash, and compare... if (uffs_TreeCompareFileName(dev, name, len, sum, node, UFFS_TYPE_DIR) == U_TRUE) { //Got it! return node; } } x = node->hash_next; } } return NULL; }
/* calculate file length, etc */ static URET _BuildTreeStepThree(uffs_Device *dev) { int i; u16 x; TreeNode *work; TreeNode *node; struct uffs_TreeSt *tree; uffs_Pool *pool; u16 blockSave; TreeNode *cache = NULL; u16 cacheSerial = INVALID_UFFS_SERIAL; tree = &(dev->tree); pool = TPOOL(dev); uffs_Perror(UFFS_MSG_NOISY, "build tree step three"); for (i = 0; i < DATA_NODE_ENTRY_LEN; i++) { x = tree->data_entry[i]; while (x != EMPTY_NODE) { work = FROM_IDX(x, pool); if (work->u.data.parent == cacheSerial) { node = cache; } else { node = uffs_TreeFindFileNode(dev, work->u.data.parent); cache = node; cacheSerial = work->u.data.parent; } if (node == NULL) { x = work->hash_next; //this data block does not belong to any file ? //should be erased. uffs_Perror(UFFS_MSG_NORMAL, "find a orphan data block:%d, " "parent:%d, serial:%d, will be erased!", work->u.data.block, work->u.data.parent, work->u.data.serial); uffs_BreakFromEntry(dev, UFFS_TYPE_DATA, work); blockSave = work->u.data.block; work->u.list.block = blockSave; uffs_FlashEraseBlock(dev, blockSave); if (HAVE_BADBLOCK(dev)) uffs_BadBlockProcess(dev, work); else uffs_TreeInsertToErasedListTail(dev, work); } else { node->u.file.len += work->u.data.len; x = work->hash_next; } } } return U_SUCC; }
TreeNode * uffs_TreeFindDataNodeByBlock(uffs_Device *dev, u16 block) { int hash; TreeNode *node; struct uffs_TreeSt *tree = &(dev->tree); u16 x; for (hash = 0; hash < DATA_NODE_ENTRY_LEN; hash++) { x = tree->data_entry[hash]; while (x != EMPTY_NODE) { node = FROM_IDX(x, TPOOL(dev)); if (node->u.data.block == block) return node; x = node->hash_next; } } return NULL; }
TreeNode * uffs_TreeFindDirNode(uffs_Device *dev, u16 serial) { int hash; u16 x; TreeNode *node; struct uffs_TreeSt *tree = &(dev->tree); hash = serial & DIR_NODE_HASH_MASK; x = tree->dir_entry[hash]; while (x != EMPTY_NODE) { node = FROM_IDX(x, TPOOL(dev)); if (node->u.dir.serial == serial) { return node; } else { x = node->hash_next; } } return NULL; }
TreeNode * uffs_TreeFindDataNode(uffs_Device *dev, u16 parent, u16 serial) { int hash; TreeNode *node; struct uffs_TreeSt *tree = &(dev->tree); u16 x; hash = GET_DATA_HASH(parent, serial); x = tree->data_entry[hash]; while(x != EMPTY_NODE) { node = FROM_IDX(x, TPOOL(dev)); if(node->u.data.parent == parent && node->u.data.serial == serial) return node; x = node->hash_next; } return NULL; }
TreeNode * uffs_TreeFindDirNodeWithParent(uffs_Device *dev, u16 parent) { int hash; u16 x; TreeNode *node; struct uffs_TreeSt *tree = &(dev->tree); for (hash = 0; hash < DIR_NODE_ENTRY_LEN; hash++) { x = tree->dir_entry[hash]; while (x != EMPTY_NODE) { node = FROM_IDX(x, TPOOL(dev)); if (node->u.dir.parent == parent) { return node; } else { x = node->hash_next; } } } return NULL; }
static URET _BuildTreeStepOne(uffs_Device *dev) { int block_lt; uffs_BlockInfo *bc = NULL; TreeNode *node; struct uffs_TreeSt *tree; uffs_Pool *pool; struct uffs_MiniHeaderSt header; URET ret = U_SUCC; struct BlockTypeStatSt st = {0, 0, 0}; tree = &(dev->tree); pool = TPOOL(dev); tree->bad = NULL; tree->bad_count = 0; tree->erased = NULL; tree->erased_tail = NULL; tree->erased_count = 0; uffs_Perror(UFFS_MSG_NOISY, "build tree step one"); // printf("s:%d e:%d\n", dev->par.start, dev->par.end); for (block_lt = dev->par.start; block_lt <= dev->par.end; block_lt++) { bc = uffs_BlockInfoGet(dev, block_lt); if (bc == NULL) { uffs_Perror(UFFS_MSG_SERIOUS, "step one:fail to get block info"); ret = U_FAIL; break; } node = (TreeNode *)uffs_PoolGet(pool); if (node == NULL) { uffs_Perror(UFFS_MSG_SERIOUS, "insufficient tree node!"); ret = U_FAIL; break; } // Need to check bad block at first ! if (uffs_FlashIsBadBlock(dev, block_lt) == U_TRUE) { node->u.list.block = block_lt; uffs_TreeInsertToBadBlockList(dev, node); uffs_Perror(UFFS_MSG_NORMAL, "found bad block %d", block_lt); } else if (uffs_IsPageErased(dev, bc, 0) == U_TRUE) { //@ read one spare: 0 // page 0 tag shows it's an erased block, we need to check the mini header status to make sure it is clean. if (uffs_LoadMiniHeader(dev, block_lt, 0, &header) == U_FAIL) { uffs_Perror(UFFS_MSG_SERIOUS, "I/O error when reading mini header !" "block %d page %d", block_lt, 0); ret = U_FAIL; break; } if (header.status != 0xFF) { // page 0 tag is clean but page data is dirty ??? // this block should be erased immediately ! uffs_FlashEraseBlock(dev, block_lt); } node->u.list.block = block_lt; if (HAVE_BADBLOCK(dev)) { uffs_Perror(UFFS_MSG_NORMAL, "New bad block (%d) discovered.", block_lt); uffs_BadBlockProcess(dev, node); } else { // page 0 is clean does not means all pages in this block are clean, // need to check this block later before use it. uffs_TreeInsertToErasedListTailEx(dev, node, 1); } } else { // this block have valid data page(s). ret = _ScanAndFixUnCleanPage(dev, bc); if (ret == U_FAIL) break; ret = _BuildValidTreeNode(dev, node, bc, &st); if (ret == U_FAIL) break; } uffs_BlockInfoPut(dev, bc); } //end of for if(ret == U_FAIL) uffs_BlockInfoPut(dev, bc); uffs_Perror(UFFS_MSG_NORMAL, "DIR %d, FILE %d, DATA %d", st.dir, st.file, st.data); return ret; }
static URET do_FindObject(uffs_FindInfo *f, uffs_ObjectInfo *info, u16 x) { URET ret = U_SUCC; TreeNode *node; uffs_Device *dev = f->dev; if (f->step == 0) { //!< working on dirs while (x != EMPTY_NODE) { node = FROM_IDX(x, TPOOL(dev)); if (node->u.dir.parent == f->serial) { f->work = node; f->pos++; if (info) ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_DIR, NULL); goto ext; } x = node->hash_next; } f->hash++; //come to next hash entry for (; f->hash < DIR_NODE_ENTRY_LEN; f->hash++) { x = dev->tree.dir_entry[f->hash]; while (x != EMPTY_NODE) { node = FROM_IDX(x, TPOOL(dev)); if (node->u.dir.parent == f->serial) { f->work = node; f->pos++; if (info) ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_DIR, NULL); goto ext; } x = node->hash_next; } } //no subdirs, then lookup files .. f->step++; f->hash = 0; x = EMPTY_NODE; } if (f->step == 1) { while (x != EMPTY_NODE) { node = FROM_IDX(x, TPOOL(dev)); if (node->u.file.parent == f->serial) { f->work = node; f->pos++; if (info) ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_FILE, NULL); goto ext; } x = node->hash_next; } f->hash++; //come to next hash entry for (; f->hash < FILE_NODE_ENTRY_LEN; f->hash++) { x = dev->tree.file_entry[f->hash]; while (x != EMPTY_NODE) { node = FROM_IDX(x, TPOOL(dev)); if (node->u.file.parent == f->serial) { f->work = node; f->pos++; if (info) ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_FILE, NULL); goto ext; } x = node->hash_next; } } //no any files, stopped. f->step++; } ret = U_FAIL; ext: return ret; }