uffs_tree.c

Go to the documentation of this file.
00001 
00006 #include "uffs/uffs_public.h"
00007 #include "uffs/uffs_os.h"
00008 #include "uffs/ubuffer.h"
00009 #include "uffs/uffs_config.h"
00010 
00011 #include <string.h>
00012 
00013 #define PFX "tree:"
00014 
00015 static void uffs_InsertToFileEntry(uffs_Device *dev, TreeNode *node);
00016 static void uffs_InsertToDirEntry(uffs_Device *dev, TreeNode *node);
00017 static void uffs_InsertToDataEntry(uffs_Device *dev, TreeNode *node);
00018 
00019 
00024 URET uffs_InitTreeBuf(uffs_Device *dev)
00025 {
00026     int size;
00027     int nums;
00028     struct ubufm *dis;
00029     int i;
00030 
00031     size = sizeof(TreeNode);
00032     nums = dev->par.end - dev->par.start + 1;
00033     dis = &(dev->tree.dis);
00034 
00035     dis->node_size = size;
00036     dis->node_nums = nums;
00037     dis->node_pool = uffs_MemAlloc(dev, size * nums);
00038     
00039     if(dis->node_pool == NULL) {
00040         uffs_Perror(UFFS_ERR_SERIOUS, PFX"fail to allocate memory for tree, %d*%d\n", size, nums);
00041         memset(dis, 0, sizeof(struct ubufm));
00042         return U_FAIL;
00043     }
00044 
00045     uBufInit(dis);
00046     dev->tree.erased = NULL;
00047     dev->tree.erased_tail = NULL;
00048     dev->tree.erasedCount = 0;
00049     dev->tree.bad = NULL;
00050     dev->tree.badCount = 0;
00051 
00052     for(i = 0; i < DIR_NODE_ENTRY_LEN; i++) {
00053         dev->tree.dirEntry[i] = EMPTY_NODE;
00054     }
00055 
00056     for(i = 0; i < FILE_NODE_ENTRY_LEN; i++) {
00057         dev->tree.fileEntry[i] = EMPTY_NODE;
00058     }
00059 
00060     for(i = 0; i < DATA_NODE_ENTRY_LEN; i++) {
00061         dev->tree.dataEntry[i] = EMPTY_NODE;
00062     }
00063 
00064     dev->tree.maxSerialNo = ROOT_DIR_ID;
00065     
00066     return U_SUCC;
00067 }
00072 URET uffs_ReleaseTreeBuf(uffs_Device *dev)
00073 {
00074     struct ubufm *dis;
00075     
00076     dis = &(dev->tree.dis);
00077     if(dis->node_pool) {
00078         uffs_MemFree(dev, dis->node_pool);
00079     }
00080     memset(dis, 0, sizeof(struct ubufm));
00081 
00082     return U_SUCC;
00083 }
00084 
00085 static u16 _GetBlockFromNode(u8 type, TreeNode *node)
00086 {
00087     switch(type){
00088     case UFFS_TYPE_DIR:
00089         return node->u.dir.block;
00090     case UFFS_TYPE_FILE:
00091         return node->u.file.block;
00092     case UFFS_TYPE_DATA:
00093         return node->u.data.block;
00094     }
00095     uffs_Perror(UFFS_ERR_SERIOUS, PFX"unkown type, X-block\n");
00096     return UFFS_INVALID_BLOCK;
00097 }
00098 
00099 static u16 _GetFatherFromNode(u8 type, TreeNode *node)
00100 {
00101     switch(type){
00102     case UFFS_TYPE_DIR:
00103         return node->u.dir.father;
00104     case UFFS_TYPE_FILE:
00105         return node->u.file.father;
00106     case UFFS_TYPE_DATA:
00107         return node->u.data.father;
00108     }
00109     uffs_Perror(UFFS_ERR_SERIOUS, PFX"unkown type, X-father\n");
00110     return UFFS_INVALID_SERIAL;
00111 }
00112 
00113 
00114 static u16 _GetSerialFromNode(u8 type, TreeNode *node)
00115 {
00116     switch(type){
00117     case UFFS_TYPE_DIR:
00118         return node->u.dir.serial;
00119     case UFFS_TYPE_FILE:
00120         return node->u.file.serial;
00121     case UFFS_TYPE_DATA:
00122         return node->u.data.serial;
00123     }
00124     uffs_Perror(UFFS_ERR_SERIOUS, PFX"unkown type, X-serial\n");
00125     return UFFS_INVALID_SERIAL;
00126 }
00127 
00134 void uffs_InsertNodeToTree(uffs_Device *dev, u8 type, TreeNode *node)
00135 {
00136     switch(type){
00137     case UFFS_TYPE_DIR:
00138         uffs_InsertToDirEntry(dev, node);
00139         break;
00140     case UFFS_TYPE_FILE:
00141         uffs_InsertToFileEntry(dev, node);
00142         break;
00143     case UFFS_TYPE_DATA:
00144         uffs_InsertToDataEntry(dev, node);
00145         break;
00146     default:
00147         uffs_Perror(UFFS_ERR_SERIOUS, PFX"unkown type, can't insert to tree\n");
00148         break;
00149     }
00150 }
00151 
00159 TreeNode * uffs_FindFromTree(uffs_Device *dev, u8 type, u16 father, u16 serial)
00160 {
00161     switch(type){
00162     case UFFS_TYPE_DIR:
00163         return uffs_FindDirNodeFromTree(dev, serial);
00164     case UFFS_TYPE_FILE:
00165         return uffs_FindFileNodeFromTree(dev, serial);
00166     case UFFS_TYPE_DATA:
00167         return uffs_FindDataNode(dev, father, serial);
00168     }
00169     uffs_Perror(UFFS_ERR_SERIOUS, PFX"unkown type, can't find node\n");
00170     return NULL;
00171 }
00172 
00173 static URET _BuildValidTreeNode(uffs_Device *dev,
00174                                 TreeNode *node,     
00175                                 uffs_blockInfo *bc)
00176 {
00177     uffs_Tags *tag;
00178     TreeNode *node_alt;
00179     u16 block, father, serial, block_alt, block_save;
00180     uffs_blockInfo *bc_alt;
00181     u8 type;
00182     UBOOL needToInsertToTree = U_FALSE;
00183     u16 page;
00184 
00185     page = uffs_FindFirstValidPage(dev, bc); //@ may only read one spare: 0
00186     if(page == UFFS_INVALID_PAGE) {
00187         //all pages are invalid ? should be erased now!
00188         uffs_Perror(UFFS_ERR_NORMAL, PFX"all pages in block %d are invalid, will be erased now!\n", bc->blockNum);
00189         
00190         dev->ops->EraseBlock(dev, bc->blockNum);
00191         uffs_ExpireBlockInfo(dev, bc, UFFS_ALL_PAGES);
00192 
00193         /* now, put this node to erased list to tail */
00194         uffs_InsertToErasedListTail(dev, node);
00195         return U_SUCC;
00196     }
00197     
00198     page = uffs_FindBestPageInBlock(dev, bc, page); //@ FIX ME! read too many spares in here
00199     tag = &(bc->spares[page].tag);  //get first page's tag
00200     block = bc->blockNum;
00201     father = tag->father;
00202     serial = tag->serial;
00203     type = tag->type;
00204 
00205     //@ FIX ME! too heavy! especially when disk full...
00206     //@ To avoid to search the alternate node, a safe-power-off mark should be set when unmount uffs
00207     //@ It need to search the alternate node only when safe-power-off mark is not set.
00208     node_alt = uffs_FindFromTree(dev, type, father, serial); 
00209 
00210     if(node_alt != NULL) {
00211         //find a alternate node !
00212         block_alt = _GetBlockFromNode(type, node_alt);
00213         if(block_alt == INVALID_UFFS_SERIAL) {
00214             uffs_Perror(UFFS_ERR_SERIOUS, PFX"invalid block ?\n");
00215             return U_FAIL;
00216         }
00217         
00218         bc_alt = uffs_GetBlockInfo(dev, block_alt);
00219         if(bc_alt == NULL) {
00220             uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't get block info \n");
00221             return U_FAIL;
00222         }
00223         uffs_LoadBlockInfo(dev, bc_alt, 0);
00224         if(uffs_IsSrcNewerThanObj(
00225             tag->blockTimeStamp, 
00226             bc_alt->spares[0].tag.blockTimeStamp) == U_TRUE) {
00227 
00228             //the node is newer than node_alt, so keep node_alt, and erase node
00229             dev->ops->EraseBlock(dev, block);
00230             uffs_ExpireBlockInfo(dev, bc, UFFS_ALL_PAGES);
00231             node->u.list.block = block;
00232             uffs_InsertToErasedListTail(dev, node);
00233             uffs_PutBlockInfo(dev, bc_alt);
00234 
00235             return U_SUCC;
00236         }
00237         else {
00238             //the node is elder than node_alt, so keep node, and erase node_alt
00239             //we use node as erased node to insert to erased list
00240 
00241             block_save = _GetBlockFromNode(type, node_alt);
00242             dev->ops->EraseBlock(dev, block_save);
00243             uffs_ExpireBlockInfo(dev, bc_alt, UFFS_ALL_PAGES);
00244             node->u.list.block = block_save;
00245             uffs_InsertToErasedListTail(dev, node);
00246             uffs_PutBlockInfo(dev, bc_alt);
00247             
00248             node = node_alt;    //use node_alt to store new informations in following
00249             needToInsertToTree = U_FALSE;
00250         }
00251     }
00252     else {
00253         needToInsertToTree = U_TRUE;
00254     }
00255 
00256     switch(type) {
00257     case UFFS_TYPE_DIR:
00258         node->u.dir.block = bc->blockNum;
00259         node->u.dir.checkSum = tag->dataSum;
00260         node->u.dir.father = tag->father;
00261         node->u.dir.serial = tag->serial;
00262         //node->u.dir.pagID = tag->pageID;
00263         //node->u.dir.ofs = (u8)page;
00264         break;
00265     case UFFS_TYPE_FILE:
00266         node->u.file.block = bc->blockNum;
00267         node->u.file.checkSum = tag->dataSum;
00268         node->u.file.father = tag->father;
00269         node->u.file.serial = tag->serial;
00270         node->u.file.len = uffs_GetBlockFileDataLength(dev, bc, UFFS_TYPE_FILE);  
00271         break;
00272     case UFFS_TYPE_DATA:
00273         node->u.data.block = bc->blockNum;
00274         node->u.data.father = tag->father;
00275         node->u.data.serial = tag->serial;
00276         if(tag->serial == 1) {
00277             tag->serial = tag->serial;
00278         }
00279         node->u.data.len = uffs_GetBlockFileDataLength(dev, bc, UFFS_TYPE_DATA); 
00280         break;
00281     }
00282 
00283     if(needToInsertToTree == U_TRUE) {
00284         uffs_InsertNodeToTree(dev, type, node);
00285     }
00286 
00287     return U_SUCC;
00288 }
00289 
00290 static URET _BuildTreeStepOne(uffs_Device *dev)
00291 {
00292     int block_lt;
00293     uffs_blockInfo *bc;
00294     TreeNode *node;
00295     struct uffs_treeSt *tree;
00296     struct ubufm *dis;
00297     URET ret = U_SUCC;
00298     
00299     tree = &(dev->tree);
00300     dis = &(tree->dis);
00301 
00302     tree->bad = NULL;
00303     tree->badCount = 0;
00304     tree->erased = NULL;
00305     tree->erased_tail = NULL;
00306     tree->erasedCount = 0;
00307 
00308     uffs_Perror(UFFS_ERR_NOISY, PFX"build tree step one\n");
00309 
00310 //  printf("s:%d e:%d\n", dev->par.start, dev->par.end);
00311     for(block_lt = dev->par.start; block_lt <= dev->par.end; block_lt++) {
00312         bc = uffs_GetBlockInfo(dev, block_lt);
00313 //      uffs_Perror(UFFS_ERR_NORMAL, PFX"loop\n");
00314         if(bc == NULL) {
00315             uffs_Perror(UFFS_ERR_SERIOUS, PFX"step one:fail to get block info\n");
00316             ret = U_FAIL;
00317             break;
00318         }
00319         node = (TreeNode *)uBufGet(dis);
00320         if(node == NULL) {
00321             uffs_Perror(UFFS_ERR_SERIOUS, PFX"insufficient tree node!\n");
00322             ret = U_FAIL;
00323             break;
00324         }
00325         //Need to check bad block at first !
00326         if(dev->flash->IsBlockBad(dev, bc) == U_TRUE) { //@ read one spare: 0
00327             node->u.list.block = block_lt;
00328             uffs_InsertToBadBlockList(dev, node);
00329         }
00330         else if(uffs_IsPageErased(dev, bc, 0) == U_TRUE) { //@ read one spare: 0
00331             //just need to check page 0 to judge whether the block is erased
00332             node->u.list.block = block_lt;
00333             uffs_InsertToErasedListTail(dev, node);
00334         }
00335         else {
00336             //uffs_Perror(UFFS_ERR_NOISY, PFX"find a valid block\n");
00337             ret = _BuildValidTreeNode(dev, node, bc);
00338             //uffs_Perror(UFFS_ERR_NOISY, PFX"valid block done!\n");
00339             if(ret == U_FAIL) break;
00340         }
00341         uffs_PutBlockInfo(dev, bc);
00342     } //end of for
00343 
00344     if(ret == U_FAIL) uffs_PutBlockInfo(dev, bc);
00345 
00346     return ret;
00347 }
00348 
00349 static URET _BuildTreeStepTwo(uffs_Device *dev)
00350 {
00351     //Random the start point of erased block to implement ware leveling
00352     u32 startCount = 0;
00353     u32 endPoint;
00354     TreeNode *node;
00355 
00356     uffs_Perror(UFFS_ERR_NOISY, PFX"build tree step two\n");
00357 
00358     endPoint = uffs_GetCurDateTime() % dev->tree.erasedCount;
00359     while(startCount < endPoint) {
00360         node = uffs_GetErased(dev);
00361         if(node == NULL) {
00362             uffs_Perror(UFFS_ERR_SERIOUS, PFX"No erased block ?\n");
00363             return U_FAIL;
00364         }
00365         uffs_InsertToErasedListTail(dev, node);
00366         startCount++;
00367     }
00368     return U_SUCC;
00369 }
00370 
00371 TreeNode * uffs_FindFileNodeFromTree(uffs_Device *dev, u16 serial)
00372 {
00373     int hash;
00374     u16 x;
00375     TreeNode *node;
00376     struct uffs_treeSt *tree = &(dev->tree);
00377 
00378     hash = serial & FILE_NODE_HASH_MASK;
00379     x = tree->fileEntry[hash];
00380     while(x != EMPTY_NODE) {
00381         node = FROM_IDX(x, &(tree->dis));
00382         if(node->u.file.serial == serial) {
00383             return node;
00384         }
00385         else {
00386             x = node->hashNext;
00387         }
00388     }
00389     return NULL;
00390 }
00391 
00392 TreeNode * uffs_FindFileNodeFromTreeWithFather(uffs_Device *dev, u16 father)
00393 {
00394     int hash;
00395     u16 x;
00396     TreeNode *node;
00397     struct uffs_treeSt *tree = &(dev->tree);
00398 
00399     for (hash = 0; hash < FILE_NODE_ENTRY_LEN; hash++) {
00400         x = tree->fileEntry[hash];
00401         while(x != EMPTY_NODE) {
00402             node = FROM_IDX(x, &(tree->dis));
00403             if(node->u.file.father == father) {
00404                 return node;
00405             }
00406             else {
00407                 x = node->hashNext;
00408             }
00409         }
00410     }
00411     return NULL;
00412 }
00413 
00414 TreeNode * uffs_FindDirNodeFromTree(uffs_Device *dev, u16 serial)
00415 {
00416     int hash;
00417     u16 x;
00418     TreeNode *node;
00419     struct uffs_treeSt *tree = &(dev->tree);
00420 
00421     hash = serial & DIR_NODE_HASH_MASK;
00422     x = tree->dirEntry[hash];
00423     while(x != EMPTY_NODE) {
00424         node = FROM_IDX(x, &(tree->dis));
00425         if(node->u.dir.serial == serial) {
00426             return node;
00427         }
00428         else {
00429             x = node->hashNext;
00430         }
00431     }
00432     return NULL;
00433 }
00434 
00435 TreeNode * uffs_FindDirNodeFromTreeWithFather(uffs_Device *dev, u16 father)
00436 {
00437     int hash;
00438     u16 x;
00439     TreeNode *node;
00440     struct uffs_treeSt *tree = &(dev->tree);
00441 
00442     for (hash = 0; hash < DIR_NODE_ENTRY_LEN; hash++) {
00443         x = tree->dirEntry[hash];
00444         while(x != EMPTY_NODE) {
00445             node = FROM_IDX(x, &(tree->dis));
00446             if(node->u.dir.father == father) {
00447                 return node;
00448             }
00449             else {
00450                 x = node->hashNext;
00451             }
00452         }
00453     }
00454     
00455     return NULL;
00456 }
00457 
00458 TreeNode * uffs_FindFileNodeByName(uffs_Device *dev, const char *name, u32 len, u16 sum, u16 father)
00459 {
00460     int i;
00461     u16 x;
00462     TreeNode *node;
00463     struct uffs_treeSt *tree = &(dev->tree);
00464     
00465     for(i = 0; i < FILE_NODE_ENTRY_LEN; i++) {
00466         x = tree->fileEntry[i];
00467         while(x != EMPTY_NODE) {
00468             node = FROM_IDX(x, &(tree->dis));
00469             if(node->u.file.checkSum == sum && node->u.file.father == father) {
00470                 //read file name from flash, and compare...
00471                 if(uffs_CompareFileNameWithTreeNode(dev, name, len, sum, node, UFFS_TYPE_FILE) == U_TRUE) {
00472                     //Got it!
00473                     return node;
00474                 }
00475             }
00476             x = node->hashNext;
00477         }
00478     }
00479     return NULL;
00480 }
00481 
00482 TreeNode * uffs_FindDataNode(uffs_Device *dev, u16 father, u16 serial)
00483 {
00484     int hash;
00485     TreeNode *node;
00486     struct uffs_treeSt *tree = &(dev->tree);
00487     u16 x;
00488 
00489     hash = GET_DATA_HASH(father, serial);
00490     x = tree->dataEntry[hash];
00491     while(x != EMPTY_NODE) {
00492         node = FROM_IDX(x, &(tree->dis));
00493 
00494         if(node->u.data.father == father &&
00495             node->u.data.serial == serial)
00496                 return node;
00497 
00498         x = node->hashNext;
00499     }
00500     return NULL;
00501 }
00502 
00503 TreeNode * uffs_FindDirNodeByBlock(uffs_Device *dev, u16 block)
00504 {
00505     int hash;
00506     TreeNode *node;
00507     struct uffs_treeSt *tree = &(dev->tree);
00508     u16 x;
00509 
00510     for(hash = 0; hash < DIR_NODE_ENTRY_LEN; hash++) {
00511         x = tree->dirEntry[hash];
00512         while(x != EMPTY_NODE) {
00513             node = FROM_IDX(x, &(tree->dis));
00514             if(node->u.dir.block == block)
00515                 return node;
00516             x = node->hashNext;
00517         }
00518     }
00519     return NULL;
00520 }
00521 
00522 TreeNode * uffs_FindErasedNodeByBlock(uffs_Device *dev, u16 block)
00523 {
00524     TreeNode *node;
00525     node = dev->tree.erased;
00526     while(node) {
00527         if(node->u.list.block == block) return node;
00528         node = node->u.list.next;
00529     }
00530         
00531     return NULL;
00532 }
00533 
00534 TreeNode * uffs_FindBadNodeByBlock(uffs_Device *dev, u16 block)
00535 {
00536     TreeNode *node;
00537     node = dev->tree.bad;
00538     while(node) {
00539         if(node->u.list.block == block) return node;
00540         node = node->u.list.next;
00541     }
00542         
00543     return NULL;
00544 }
00545 
00546 TreeNode * uffs_FindFileNodeByBlock(uffs_Device *dev, u16 block)
00547 {
00548     int hash;
00549     TreeNode *node;
00550     struct uffs_treeSt *tree = &(dev->tree);
00551     u16 x;
00552 
00553     for(hash = 0; hash < FILE_NODE_ENTRY_LEN; hash++) {
00554         x = tree->fileEntry[hash];
00555         while(x != EMPTY_NODE) {
00556             node = FROM_IDX(x, &(tree->dis));
00557             if(node->u.file.block == block)
00558                 return node;
00559             x = node->hashNext;
00560         }
00561     }
00562     return NULL;
00563 }
00564 
00565 TreeNode * uffs_FindDataNodeByBlock(uffs_Device *dev, u16 block)
00566 {
00567     int hash;
00568     TreeNode *node;
00569     struct uffs_treeSt *tree = &(dev->tree);
00570     u16 x;
00571 
00572     for(hash = 0; hash < DATA_NODE_ENTRY_LEN; hash++) {
00573         x = tree->dataEntry[hash];
00574         while(x != EMPTY_NODE) {
00575             node = FROM_IDX(x, &(tree->dis));
00576             if(node->u.data.block == block)
00577                 return node;
00578             x = node->hashNext;
00579         }
00580     }
00581     return NULL;
00582 }
00583 
00584 TreeNode * uffs_FindNodeByBlock(uffs_Device *dev, u16 block, int *region)
00585 {
00586     TreeNode *node = NULL;
00587     if(*region & SEARCH_REGION_DATA) {
00588         node = uffs_FindDataNodeByBlock(dev, block);
00589         if(node) {
00590             *region &= SEARCH_REGION_DATA;
00591             return node;
00592         }
00593     }
00594     if(*region & SEARCH_REGION_FILE) {
00595         node = uffs_FindFileNodeByBlock(dev, block);
00596         if(node) {
00597             *region &= SEARCH_REGION_FILE;
00598             return node;
00599         }
00600     }
00601     if(*region & SEARCH_REGION_DIR) {
00602         node = uffs_FindDirNodeByBlock(dev, block);
00603         if(node) {
00604             *region &= SEARCH_REGION_DIR;
00605             return node;
00606         }
00607     }
00608     if(*region & SEARCH_REGION_ERASED) {
00609         node = uffs_FindErasedNodeByBlock(dev, block);
00610         if(node) {
00611             *region &= SEARCH_REGION_ERASED;
00612             return node;
00613         }
00614     }
00615     if(*region & SEARCH_REGION_BAD) {
00616         node = uffs_FindBadNodeByBlock(dev, block);
00617         if(node) {
00618             *region &= SEARCH_REGION_BAD;
00619             return node;
00620         }
00621     }
00622     return node;
00623 }
00624 
00625 TreeNode * uffs_FindDirNodeByName(uffs_Device *dev, const char *name, u32 len, u16 sum, u16 father)
00626 {
00627     int i;
00628     u16 x;
00629     TreeNode *node;
00630     struct uffs_treeSt *tree = &(dev->tree);
00631     
00632     for(i = 0; i < DIR_NODE_ENTRY_LEN; i++) {
00633         x = tree->dirEntry[i];
00634         while(x != EMPTY_NODE) {
00635             node = FROM_IDX(x, &(tree->dis));
00636             if(node->u.dir.checkSum == sum && node->u.dir.father == father) {
00637                 //read file name from flash, and compare...
00638                 if(uffs_CompareFileNameWithTreeNode(dev, name, len, sum, node, UFFS_TYPE_DIR) == U_TRUE) {
00639                     //Got it!
00640                     return node;
00641                 }
00642             }
00643             x = node->hashNext;
00644         }
00645     }
00646     return NULL;
00647 
00648 }
00649 
00650 UBOOL uffs_CompareFileName(const char *src, int src_len, const char *des)
00651 {
00652     while(src_len-- > 0) {
00653         if(*src++ != *des++) return U_FALSE;
00654     }
00655     return U_TRUE;
00656 }
00657 
00658 UBOOL uffs_CompareFileNameWithTreeNode(uffs_Device *dev, const char *name, u32 len, u16 sum, TreeNode *node, int type)
00659 {
00660     u16 page;
00661     uffs_blockInfo *bc;
00662     uffs_Tags *tag;
00663     URET ret = U_FAIL;
00664     uffs_fileInfo fi;
00665     u16 block;
00666 
00667     if (type == UFFS_TYPE_DIR)
00668         block = node->u.dir.block;
00669     else
00670         block = node->u.file.block;
00671 
00672     bc = uffs_GetBlockInfo(dev, block);
00673 
00674     if(bc == NULL) {
00675         uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't get block info %d\n", block);
00676         return U_FALSE;
00677     }
00678 
00679     //dir|file name must resident in pageID == 0
00680     uffs_LoadBlockInfo(dev, bc, UFFS_ALL_PAGES);
00681     page = uffs_FindBestPageInBlock(dev, bc, 0);
00682 
00683     tag = &(bc->spares[page].tag);
00684     if(tag->dataSum != sum) {
00685         uffs_Perror(UFFS_ERR_NORMAL, PFX"the obj's sum in tag is different with given sum!\n");
00686         uffs_PutBlockInfo(dev, bc);
00687         return U_FALSE;
00688     }
00689 
00690     ret = dev->ops->ReadPageData(dev, block, page, (u8 *)(&fi), 0, sizeof(uffs_fileInfo));
00691     if(ret == U_FAIL) {
00692         uffs_PutBlockInfo(dev, bc);
00693         uffs_Perror(UFFS_ERR_SERIOUS, PFX"I/O error ?\n");
00694         return U_FALSE;
00695     }
00696 
00697     if(fi.name_len == len) {
00698         if(uffs_CompareFileName(fi.name, fi.name_len, name) == U_TRUE) {
00699             uffs_PutBlockInfo(dev, bc);
00700             return U_TRUE;
00701         }
00702     }
00703 
00704     uffs_PutBlockInfo(dev, bc);
00705     return U_FALSE;
00706 }
00707 
00708 
00709 /* calculate file length */
00710 static URET _BuildTreeStepThree(uffs_Device *dev)
00711 {
00712     int i;
00713     u16 x;
00714     TreeNode *work;
00715     TreeNode *node;
00716     struct uffs_treeSt *tree;
00717     struct ubufm *dis;
00718     u16 blockSave;
00719 
00720     TreeNode *cache = NULL;
00721     u16 cacheSerial = INVALID_UFFS_SERIAL;
00722 
00723 
00724     //FIX ME!! a cache system MUST be designed to accelerate this procedure
00725     //FIX ME!! otherwise a huge file nodes or data nodes would drag system from fast booting
00726 
00727     tree = &(dev->tree);
00728     dis = &(tree->dis);
00729 
00730     uffs_Perror(UFFS_ERR_NOISY, PFX"build tree step three\n");
00731 
00732     for(i = 0; i < DATA_NODE_ENTRY_LEN; i++) {
00733         x = tree->dataEntry[i];
00734         while(x != EMPTY_NODE) {
00735             work = FROM_IDX(x, dis);
00736             if(work->u.data.father == cacheSerial) {
00737                 node = cache;
00738             }
00739             else {
00740                 node = uffs_FindFileNodeFromTree(dev, work->u.data.father);
00741                 cache = node;
00742                 cacheSerial = work->u.data.father;
00743             }
00744             if(node == NULL) {
00745                 x = work->hashNext;
00746                 //this data block do not belong any file ?
00747                 //should be erased.
00748                 uffs_Perror(UFFS_ERR_NORMAL, PFX"find a orphan data block:%d, father:%d, serial:%d, will be erased!\n", 
00749                     work->u.data.block, work->u.data.father, work->u.data.serial);
00750                 uffs_BreakFromEntry(dev, UFFS_TYPE_DATA, work);
00751                 blockSave = work->u.data.block;
00752                 work->u.list.block = blockSave;
00753                 dev->ops->EraseBlock(dev, blockSave);
00754                 uffs_InsertToErasedListTail(dev, work);
00755             }
00756             else {
00757                 node->u.file.len += work->u.data.len;
00758                 x = work->hashNext;
00759             }
00760         }
00761     }
00762 
00763     return U_SUCC;
00764 }
00765 
00770 URET uffs_BuildTree(uffs_Device *dev)
00771 {
00772     URET ret;
00773 
00774     /***** step one: scan all page spares, classify DIR/FILE/DATA nodes,
00775             check bad blocks/uncompleted(conflicted) blocks as well *****/
00776     /* if the disk is big and full filled of data this step could be the most time consuming .... */
00777     ret = _BuildTreeStepOne(dev);
00778     if(ret != U_SUCC) {
00779         uffs_Perror(UFFS_ERR_SERIOUS, PFX"build tree step one fail!\n");
00780         return ret;
00781     }
00782 
00783     /***** step two: randomize the erased blocks, for ware-leveling purpose *****/
00784     /* this step is very fast :) */
00785     ret = _BuildTreeStepTwo(dev);
00786     if(ret != U_SUCC) {
00787         uffs_Perror(UFFS_ERR_SERIOUS, PFX"build tree step two fail!\n");
00788         return ret;
00789     }
00790 
00791     /***** step three: check DATA nodes, find orphan nodes and erase them *****/
00792     /* if there are a lot of files and disk is fully filled, this step could be very time consuming ... */
00793     ret = _BuildTreeStepThree(dev);
00794     if(ret != U_SUCC) {
00795         uffs_Perror(UFFS_ERR_SERIOUS, PFX"build tree step three fail!\n");
00796         return ret;
00797     }
00798     
00799     return U_SUCC;
00800 }
00801 
00807 u16 uffs_FindFreeFsnSerial(uffs_Device *dev)
00808 {
00809     u16 i;
00810     TreeNode *node;
00811 
00812     //TODO!! Do it need to implement a faster serial number generating method?
00813     //       it depends on how often creating files or directories
00814 
00815     for(i = ROOT_DIR_ID + 1; i < MAX_UFFS_SERIAL; i++) {
00816         node = uffs_FindDirNodeFromTree(dev, i);
00817         if(node == NULL) {
00818             node = uffs_FindFileNodeFromTree(dev, i);
00819             if(node == NULL) return i;
00820         }
00821     }
00822     return INVALID_UFFS_SERIAL;
00823 }
00824 
00825 TreeNode * uffs_GetErased(uffs_Device *dev)
00826 {
00827     TreeNode *node = NULL;
00828     if(dev->tree.erased) {
00829         node = dev->tree.erased;
00830         dev->tree.erased->u.list.prev = NULL;
00831         dev->tree.erased = dev->tree.erased->u.list.next;
00832         if(dev->tree.erased == NULL) dev->tree.erased_tail = NULL;
00833     }
00834     dev->tree.erasedCount--;
00835 
00836     return node;
00837 }
00838 
00839 static void _InsertToEntry(uffs_Device *dev, u16 *entry, int hash, TreeNode *node)
00840 {
00841     struct uffs_treeSt *tree = &(dev->tree);
00842 
00843     node->hashNext = entry[hash];
00844 #ifdef TREE_NODE_USE_DOUBLE_LINK
00845     node->hashPrev = EMPTY_NODE;
00846     if(entry[hash] != EMPTY_NODE) {
00847         FROM_IDX(entry[hash], &(tree->dis))->hashPrev = TO_IDX(node, &(tree->dis));
00848     }
00849 #endif
00850     entry[hash] = TO_IDX(node, &(tree->dis));
00851 }
00852 
00853 //static void _BreakFromEntry(uffs_Device *dev, u16 *entry, int hash, TreeNode *node)
00854 //{
00855 //  TreeNode *work;
00856 //  struct uffs_treeSt *tree = &(dev->tree);
00857 //  struct ubufm *dis = &(tree->dis);
00858 //  
00859 //  if(node->hashPrev != EMPTY_NODE) {
00860 //      work = FROM_IDX(node->hashPrev, dis);
00861 //      work->hashNext = node->hashNext;
00862 //  }
00863 //  if(node->hashNext != EMPTY_NODE) {
00864 //      work = FROM_IDX(node->hashNext, dis);
00865 //      work->hashPrev = node->hashPrev;
00866 //  }
00867 //  if(entry[hash] == TO_IDX(node, dis)) {
00868 //      entry[hash] = node->hashNext;
00869 //  }
00870 //}
00871 
00872 #ifndef TREE_NODE_USE_DOUBLE_LINK
00873 TreeNode * _FindPrevNodeFromEntry(uffs_Device *dev, u16 start, u16 find)
00874 {
00875     TreeNode *work;
00876     while (start != EMPTY_NODE) {
00877         work = FROM_IDX(start, &(dev->tree.dis));
00878         if (work->hashNext == find) {
00879             return work;
00880         }
00881     }
00882     return NULL;
00883 }
00884 #endif
00885 
00889 void uffs_BreakFromEntry(uffs_Device *dev, u8 type, TreeNode *node)
00890 {
00891     u16 *entry;
00892     int hash;
00893     TreeNode *work;
00894 
00895     switch(type) {
00896     case UFFS_TYPE_DIR:
00897         hash = GET_DIR_HASH(node->u.dir.serial);
00898         entry = &(dev->tree.dirEntry[hash]);
00899         break;
00900     case UFFS_TYPE_FILE:
00901         hash = GET_FILE_HASH(node->u.file.serial);
00902         entry = &(dev->tree.fileEntry[hash]);
00903         break;
00904     case UFFS_TYPE_DATA:
00905         hash = GET_DATA_HASH(node->u.data.father, node->u.data.serial);
00906         entry = &(dev->tree.dataEntry[hash]);
00907         break;
00908     default:
00909         uffs_Perror(UFFS_ERR_SERIOUS, PFX"unknown type when break...\n");
00910         return;
00911     }
00912 #ifdef TREE_NODE_USE_DOUBLE_LINK
00913     if(node->hashPrev != EMPTY_NODE) {
00914         work = FROM_IDX(node->hashPrev, &(dev->tree.dis));
00915         work->hashNext = node->hashNext;
00916     }
00917     if(node->hashNext != EMPTY_NODE) {
00918         work = FROM_IDX(node->hashNext, &(dev->tree.dis));
00919         work->hashPrev = node->hashPrev;
00920     }
00921 #else
00922     if ((work = _FindPrevNodeFromEntry(dev, *entry, TO_IDX(node, &(dev->tree.dis)))) != NULL) {
00923         work->hashNext = node->hashNext;
00924     }
00925 #endif
00926 
00927     if(*entry == TO_IDX(node, &(dev->tree.dis))) {
00928         *entry = node->hashNext;
00929     }
00930 }
00931 
00932 static void uffs_InsertToFileEntry(uffs_Device *dev, TreeNode *node)
00933 {
00934     _InsertToEntry(dev, dev->tree.fileEntry, GET_FILE_HASH(node->u.file.serial), node);
00935 }
00936 
00937 static void uffs_InsertToDirEntry(uffs_Device *dev, TreeNode *node)
00938 {
00939     _InsertToEntry(dev, dev->tree.dirEntry, GET_DIR_HASH(node->u.dir.serial), node);
00940 }
00941 
00942 static void uffs_InsertToDataEntry(uffs_Device *dev, TreeNode *node)
00943 {
00944     _InsertToEntry(dev, dev->tree.dataEntry, GET_DATA_HASH(node->u.data.father, node->u.data.serial), node);
00945 }
00946 
00947 void uffs_InsertToErasedListHead(uffs_Device *dev, TreeNode *node)
00948 {
00949     struct uffs_treeSt *tree;
00950     tree = &(dev->tree);
00951 
00952     node->u.list.next = tree->erased;
00953     node->u.list.prev = NULL;
00954     if(tree->erased) {
00955         tree->erased->u.list.prev = node;
00956     }
00957 
00958     tree->erased = node;
00959     if(node->u.list.next == tree->erased_tail) {
00960         tree->erased_tail = node;
00961     }
00962     tree->erasedCount++;
00963 }
00964 
00965 void uffs_InsertToErasedListTail(uffs_Device *dev, TreeNode *node)
00966 {
00967     struct uffs_treeSt *tree;
00968     tree = &(dev->tree);
00969 
00970     node->u.list.next = NULL;
00971     node->u.list.prev = tree->erased_tail;
00972     if(tree->erased_tail) {
00973         tree->erased_tail->u.list.next = node;
00974     }
00975 
00976     tree->erased_tail = node;
00977     if(tree->erased == NULL) {
00978         tree->erased = node;
00979     }
00980     tree->erasedCount++;
00981 }
00982 
00983 void uffs_InsertToBadBlockList(uffs_Device *dev, TreeNode *node)
00984 {
00985     struct uffs_treeSt *tree;
00986     tree = &(dev->tree);
00987     node->u.list.prev = NULL;
00988     node->u.list.next = tree->bad;
00989     if(tree->bad) {
00990         tree->bad->u.list.prev = node;
00991     }
00992     tree->bad = node;
00993     tree->badCount++;
00994 }
00995 
00999 void uffs_SetTreeNodeBlock(u8 type, TreeNode *node, u16 block)
01000 {
01001     switch(type) {
01002     case UFFS_TYPE_FILE:
01003         node->u.file.block = block;
01004         break;
01005     case UFFS_TYPE_DIR:
01006         node->u.dir.block = block;
01007         break;
01008     case UFFS_TYPE_DATA:
01009         node->u.data.block = block;
01010         break;
01011     }
01012 }
01013 

Generated on Sat Mar 17 15:45:45 2007 for uffs-doc by  doxygen 1.5.0