uffs_fs.c

Go to the documentation of this file.
00001 
00007 #include "uffs/uffs_fs.h"
00008 #include "uffs/uffs_config.h"
00009 #include "uffs/ubuffer.h"
00010 #include "uffs/uffs_ecc.h"
00011 #include "uffs/uffs_badblock.h"
00012 #include "uffs/uffs_os.h"
00013 #include <string.h>
00014 
00015 #define PFX "fs:"
00016 
00017 #define GET_SERIAL_FROM_NODE(obj) ((obj)->type == UFFS_TYPE_DIR ? (obj)->node->u.dir.serial : (obj)->node->u.file.serial)
00018 #define GET_BLOCK_FROM_NODE(obj) ((obj)->type == UFFS_TYPE_DIR ? (obj)->node->u.dir.block : (obj)->node->u.file.block)
00019 
00020 static URET _PrepareOpenObj(uffs_Object *obj, const char *fullname, int oflag, int pmode);
00021 static URET _CreateObjectUnder(uffs_Object *obj);
00022 static void _ReleaseObjectResource(uffs_Object *obj);
00023 
00024 
00025 static int _object_buf[sizeof(uffs_Object) * MAX_OBJECT_HANDLE / sizeof(int)];
00026 static struct ubufm _object_dis = {
00027     _object_buf,
00028     sizeof(uffs_Object),
00029     MAX_OBJECT_HANDLE,
00030     NULL,
00031 };
00032 
00033 URET uffs_InitObjectBuf(void)
00034 {
00035     if(uBufInit(&_object_dis) < 0) return U_FAIL;
00036     else return U_SUCC;
00037 }
00038 
00039 uffs_Object * uffs_GetObject(void)
00040 {
00041     uffs_Object * obj;
00042     obj = (uffs_Object *)uBufGet(&_object_dis);
00043     if (obj) {
00044         memset(obj, 0, sizeof(uffs_Object));
00045         obj->openSucc = U_FALSE;
00046     }
00047     return obj;
00048 }
00049 
00050 void uffs_PutObject(uffs_Object *obj)
00051 {
00052     uBufPut(obj, &_object_dis);
00053 }
00054 
00055 int uffs_GetObjectIndex(uffs_Object *obj)
00056 {
00057     return uBufGetIndex(obj, &_object_dis);
00058 }
00059 
00060 uffs_Object * uffs_GetObjectByIndex(int idx)
00061 {
00062     return (uffs_Object *) uBufGetBufByIndex(idx, &_object_dis);
00063 }
00064 
00065 static void uffs_ObjectDevLock(uffs_Object *obj)
00066 {
00067     if (obj) {
00068         if (obj->dev) {
00069             if (obj->devLockCount == 0) {
00070                 uffs_DeviceLock(obj->dev);
00071             }
00072             obj->devLockCount++;
00073         }
00074     }
00075 }
00076 
00077 static void uffs_ObjectDevUnLock(uffs_Object *obj)
00078 {
00079     if (obj) {
00080         if (obj->dev) {
00081             obj->devLockCount--;
00082             if (obj->devLockCount == 0) {
00083                 uffs_DeviceUnLock(obj->dev);
00084             }
00085         }
00086     }
00087 }
00088 
00090 static int _getpath(const char *fullname, char *path)
00091 {
00092     int i;
00093     int len;
00094     int found = 0;
00095 
00096     if(fullname[0] == 0) return 0;
00097     if(fullname[0] != '/') {
00098         path[0] = '/';
00099         strcpy(path + 1, fullname);
00100     }
00101     else {
00102         strcpy(path, fullname);
00103     }
00104 
00105     len = strlen(path);
00106     for (i = len; i > 0 && path[i] != '/'; i--) {
00107         path[i] = '\0';
00108     }
00109 
00110     return i + 1;
00111 }
00112 
00113 static const char * _getfilename(const char *all)
00114 {
00115     int i;
00116     int len;
00117 
00118     len = strlen(all);
00119 
00120     for(i = len - 1; i >= 0; i--){
00121         if(all[i] == '/'){
00122             return all + i + 1;
00123         }
00124     }
00125     return all;
00126 }
00127 
00128 URET uffs_CreateObject(uffs_Object *obj, const char *fullname, int oflag, int pmode)
00129 {
00130     URET ret = U_FAIL;
00131 
00132     oflag |= UO_CREATE;
00133 
00134     if (_PrepareOpenObj(obj, fullname, oflag, pmode) == U_SUCC) {
00135         uffs_ObjectDevLock(obj);
00136         ret  = _CreateObjectUnder(obj);
00137         uffs_ObjectDevUnLock(obj);
00138     }
00139 
00140     return ret;
00141 }
00142 
00143 
00144 
00145 static int find_maxMatchedMountPoint(const char *path)
00146 {
00147     char buf[MAX_PATH_LENGTH+2] = {0};
00148     int pos;
00149     uffs_Device *dev;
00150 
00151     pos = strlen(path);
00152     memcpy(buf, path, pos + 1);
00153 
00154     while(pos > 0) {
00155         if ((dev = uffs_GetDevice(buf)) != NULL ) {
00156             uffs_PutDevice(dev);
00157             return pos;
00158         }
00159         else {
00160             buf[pos - 1] = '\0'; //replace the '/' with '\0'
00161 
00162             //back forward search the next '/'
00163             for (; pos > 0 && buf[pos-1] != '/'; pos--)
00164                 buf[pos-1] = '\0';
00165         }
00166     };
00167 
00168     return pos;
00169 }
00170 
00171 static URET _CreateObjectUnder(uffs_Object *obj)
00172 {
00176     uffs_Buf *buf = NULL;
00177     uffs_fileInfo fi, *pfi;
00178     URET ret;
00179 
00180     TreeNode *node;
00181 
00182     if (obj->type == UFFS_TYPE_DIR) {
00183         //find out whether have file with the same name
00184         node = uffs_FindFileNodeByName(obj->dev, obj->name, obj->nameLen, obj->sum, obj->father);
00185         if (node != NULL) {
00186             obj->err = UEEXIST;
00187             return U_FAIL;
00188         }
00189         obj->node = uffs_FindDirNodeByName(obj->dev, obj->name, obj->nameLen, obj->sum, obj->father);
00190     }
00191     else {
00192         //find out whether have dir with the same name
00193         node = uffs_FindDirNodeByName(obj->dev, obj->name, obj->nameLen, obj->sum, obj->father);
00194         if (node != NULL) {
00195             obj->err = UEEXIST;
00196             return U_FAIL;
00197         }
00198         obj->node = uffs_FindFileNodeByName(obj->dev, obj->name, obj->nameLen, obj->sum, obj->father);
00199     }
00200 
00201     if (obj->node) {
00202         /* dir|file already exist, truncate it to zero length */
00203         obj->serial = GET_SERIAL_FROM_NODE(obj);
00204 
00205         buf = uffs_BufGetEx(obj->dev, obj->type, obj->node, 0);
00206 
00207         if(buf == NULL) {
00208             uffs_Perror(UFFS_ERR_SERIOUS, PFX"found in tree, but can' load buffer ?\n");
00209             goto err;
00210         }
00211 
00212         pfi = (uffs_fileInfo *)(buf->data);
00213         obj->access = pfi->access;
00214         obj->attr = pfi->attr;
00215         obj->createTime = pfi->createTime;
00216         obj->lastModify = pfi->lastModify;
00217         uffs_BufPut(obj->dev, buf);
00218 
00219         obj->pos = 0;
00220 
00221         obj->openSucc = U_TRUE;
00222         ret = uffs_TruncateObject(obj, 0);
00223         if (ret != U_SUCC) {
00224             obj->openSucc = U_FALSE;
00225         }
00226         return ret;
00227     }
00228 
00229     /* dir|file does not exist, create a new one */
00230     obj->serial = uffs_FindFreeFsnSerial(obj->dev);
00231 
00232     if(obj->dev->tree.erasedCount < MINIMUN_ERASED_BLOCK) {
00233         uffs_Perror(UFFS_ERR_NOISY, PFX"insufficient block in create obj\n");
00234         goto err;
00235     }
00236 
00237     buf = uffs_BufNew(obj->dev, obj->type, obj->father, obj->serial, 0);
00238     if(buf == NULL) {
00239         uffs_Perror(UFFS_ERR_SERIOUS, PFX"Can't new buffer when create obj!\n");
00240         goto err;
00241     }
00242 
00243     memset(&fi, 0, sizeof(uffs_fileInfo));
00244     memcpy(fi.name, obj->name, obj->nameLen);
00245     fi.name[obj->nameLen] = '\0';
00246     fi.name_len = obj->nameLen;
00247     fi.access = 0;
00248     fi.attr |= FILE_ATTR_WRITE;
00249     if (obj->type == UFFS_TYPE_DIR)
00250         fi.attr |= FILE_ATTR_DIR;
00251     fi.createTime = fi.lastModify = uffs_GetCurDateTime();
00252 
00253     obj->createTime = fi.createTime;
00254     obj->lastModify = fi.lastModify;
00255     obj->attr = fi.attr;
00256     obj->access = fi.access;
00257 
00258     uffs_BufWrite(obj->dev, buf, &fi, 0, sizeof(uffs_fileInfo));
00259     uffs_BufPut(obj->dev, buf);
00260 
00261     //flush buffer immediately, so that the new node will be inserted into the tree
00262     uffs_BufFlush(obj->dev);
00263 
00264     //update obj->node: after buf flushed, the NEW node can be found in the tree
00265     if (obj->type == UFFS_TYPE_DIR)
00266         obj->node = uffs_FindDirNodeFromTree(obj->dev, obj->serial);
00267     else
00268         obj->node = uffs_FindFileNodeFromTree(obj->dev, obj->serial);
00269 
00270     if(obj->node == NULL) {
00271         uffs_Perror(UFFS_ERR_NOISY, PFX"Can't find the node in the tree ?\n");
00272         goto err;
00273     }
00274 
00275     if (obj->type == UFFS_TYPE_DIR) {
00276         //do nothing for dir ...
00277     }
00278     else {
00279         obj->node->u.file.len = 0;  //init the length to 0
00280     }
00281 
00282     if (HAVE_BADBLOCK(obj->dev)) uffs_RecoverBadBlock(obj->dev);
00283     obj->openSucc = U_TRUE;
00284 
00285     return U_SUCC;
00286 
00287 err:
00288     if (buf && obj->dev) {
00289         uffs_BufPut(obj->dev, buf);
00290         buf = NULL;
00291     }
00292 
00293     return U_FAIL;
00294 }
00295 
00296 
00297 static URET _OpenObjectUnder(uffs_Object *obj)
00298 {
00299     uffs_Buf *buf = NULL;
00300     uffs_fileInfo *fi = NULL;
00301 
00302     uffs_DeviceLock(obj->dev);
00303 
00304     /*************** init level 1 ***************/
00305     if (obj->type == UFFS_TYPE_DIR) {
00306         obj->node = uffs_FindDirNodeByName(obj->dev, obj->name, obj->nameLen, obj->sum, obj->father);
00307     }
00308     else {
00309         obj->node = uffs_FindFileNodeByName(obj->dev, obj->name, obj->nameLen, obj->sum, obj->father);
00310     }
00311 
00312     if(obj->node == NULL) {
00313         /* dir|file not exist */
00314         if(obj->oflag & UO_CREATE){
00315             //create dir|file
00316             return _CreateObjectUnder(obj);
00317         }
00318         else {
00319             obj->err = UENOENT;
00320             //uffs_Perror(UFFS_ERR_NOISY, PFX"dir or file not found\n");
00321             goto err;
00322         }
00323     }
00324 
00325     obj->serial = GET_SERIAL_FROM_NODE(obj);
00326 
00327     buf = uffs_BufGetEx(obj->dev, obj->type, obj->node, 0);
00328 
00329     if(buf == NULL) {
00330         uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't get buf when open!\n");
00331         goto err;
00332     }
00333 
00334     fi = (uffs_fileInfo *)(buf->data);
00335     obj->attr = fi->attr;
00336     obj->createTime = fi->createTime;
00337     obj->lastModify = fi->lastModify;
00338     obj->access = fi->access;
00339     uffs_BufPut(obj->dev, buf);
00340 
00341     if((obj->oflag & (UO_CREATE | UO_EXCL)) == (UO_CREATE | UO_EXCL)){
00342         obj->err = UEEXIST;
00343         goto err;
00344     }
00345 
00346     if(obj->oflag & UO_TRUNC) {
00347         if(uffs_TruncateObject(obj, 0) == U_FAIL){
00348             //obj->err will be set in uffs_TruncateObject
00349             goto err;
00350         }
00351     }
00352 
00353     obj->err = UENOERR;
00354 
00355     obj->openSucc = U_TRUE;
00356     uffs_DeviceUnLock(obj->dev);
00357 
00358     return U_SUCC;
00359 
00360 err:
00361     if(obj->name) {
00362         uffs_MemFree(obj->dev, obj->name);
00363         obj->name = NULL;
00364     }
00365     if(obj->dev) {
00366         uffs_DeviceUnLock(obj->dev);
00367         uffs_PutDevice(obj->dev);
00368         obj->dev = NULL;
00369     }
00370 
00371     return U_FAIL;
00372 }
00373 
00374 static int getPathPart(const char *path, int *pos)
00375 {
00376     int len = 0;
00377 
00378     for (len = 0; path[len+(*pos)] != '\0' && path[len+(*pos)] != '/'; len++) ;
00379 
00380     *pos += len;
00381 
00382     return len;
00383 }
00384 
00385 static u16 _GetDirSerial(uffs_Device *dev, const char *path, u16 father)
00386 {
00387     int pos = 0;
00388     int pos_last = 0;
00389     int len = 0;
00390     char part[MAX_FILENAME_LENGTH+2] = {0};
00391     TreeNode * node;
00392     u16 sum;
00393     u16 serial = father;
00394 
00395     while((len = getPathPart(path, &pos)) > 0) {
00396         memcpy(part, path + pos_last, len);
00397         part[len] = '\0';
00398         sum = uffs_MakeSum16(part, len);
00399         node = uffs_FindDirNodeByName(dev, part, len, sum, serial);
00400         if (node) {
00401             serial = node->u.dir.serial;
00402             pos_last = ++pos;
00403         }
00404         else {
00405             return INVALID_UFFS_SERIAL;
00406         }
00407     }
00408 
00409     return serial;
00410 }
00411 
00412 //static int _get_mount_point_from_full(const char *full)
00413 //{
00414 //
00415 //}
00416 
00417 static URET _PrepareOpenObj(uffs_Object *obj, const char *fullname, int oflag, int pmode)
00418 {
00419     URET ret = U_SUCC;
00420     char buf[MAX_PATH_LENGTH+2] = {0};
00421     char mount[MAX_PATH_LENGTH+2] = {0};
00422     char *start_path = mount;
00423     int pos;
00424     int len;
00425     char *name;
00426 
00427     obj->dev = NULL;
00428     obj->name = NULL;
00429 
00430     if((oflag & (UO_WRONLY | UO_RDWR)) == (UO_WRONLY | UO_RDWR)){
00431         /* UO_WRONLY and UO_RDWR can't appear together */
00432         uffs_Perror(UFFS_ERR_NOISY, PFX"UO_WRONLY and UO_RDWR can't appear together\n");
00433         obj->err = UEINVAL;
00434         return U_FAIL;
00435     }
00436 
00437     obj->pos = 0;
00438 
00439     /************** init level 0 **************/
00440     obj->oflag = oflag;
00441     obj->pmode = pmode;
00442 
00443     // assume: fullname = "/abc/def/xyz"  | "/abc"
00444     // mount point: "/abc/"               | "/"
00445     if (oflag & UO_DIR) {
00447         obj->type = UFFS_TYPE_DIR;
00448         len = strlen(fullname);
00449         memcpy(buf, fullname, len);
00450         if (buf[len - 1] != '/') {
00451             buf[len] = '/';
00452             buf[len+1] = '\0';
00453         }
00454         // now, we got the buf as: "/abc/def/xyz/"  | "/abc/"
00455 
00456     }
00457     else {
00459         obj->type = UFFS_TYPE_FILE;
00460 
00461         _getpath(fullname, buf);
00462         // now, we got the buf as: "/abc/def/"      | "/"
00463     }
00464 
00465     pos = find_maxMatchedMountPoint(buf);
00466     if (pos == 0) {
00467         /* can't not find any mount point from the path ??? */
00468         //uffs_Perror(UFFS_ERR_NOISY, PFX"Can't find any mount point from the path %s\n", buf);
00469         obj->err = UENOENT;
00470         return U_FAIL;
00471     }
00472 
00473     // get mount point: "/abc/" | "/"
00474     memcpy(mount, buf, pos);
00475     mount[pos] = '\0';
00476 
00477     obj->dev = uffs_GetDevice(mount);
00478     if (obj->dev == NULL) {
00479         obj->err = UENOENT;
00480         return U_FAIL;
00481     }
00482 
00483     uffs_DeviceLock(obj->dev);
00484 
00485     //here is a good chance to deal with bad block ...
00486     if (HAVE_BADBLOCK(obj->dev)) uffs_RecoverBadBlock(obj->dev);
00487 
00488     // get the rest name (fullname - mount point): "/def/xyz"   | "/abc"
00489     len = strlen(fullname) - strlen(mount) + 1;
00490     memcpy(buf, fullname + strlen(mount) - 1, len);
00491     buf[len] = '\0';
00492 
00493     // get the name: "xyz"  |   "abc"
00494     name = (char *) _getfilename(buf);
00495 
00496     //get start path: "/def/"   | "/"
00497     _getpath(buf, start_path);
00498 
00499     // get sub folder serial number under "/":  "def/" | ""
00500     obj->father = _GetDirSerial(obj->dev, start_path + 1, ROOT_DIR_ID);
00501     if (obj->father == INVALID_UFFS_SERIAL) {
00502         uffs_Perror(UFFS_ERR_NORMAL, PFX"can't open path %s\n", start_path);
00503         obj->err = UENOENT;
00504         goto err;
00505     }
00506 
00507     obj->nameLen = strlen(name);
00508     obj->name = (char *) uffs_MemAlloc(obj->dev, obj->nameLen + 4);
00509     if(obj->name == NULL) {
00510         uffs_Perror(UFFS_ERR_SERIOUS, PFX"open, allocate mem fail when open\n");
00511         obj->err = UENOMEM;
00512         goto err;
00513     }
00514     memcpy(obj->name, name, obj->nameLen);
00515     obj->name[obj->nameLen] = '\0';
00516     obj->sum = uffs_MakeSum16(obj->name, obj->nameLen);
00517     obj->encode = UFFS_DEFAULT_ENCODE;
00518     obj->pagesOnHead = obj->dev->attr.pages_per_block - 1;
00519 
00520     return U_SUCC;
00521 
00522 err:
00523     if (obj->name) {
00524         uffs_MemFree(obj->dev, obj->name);
00525         obj->name = NULL;
00526     }
00527     if (obj->dev) {
00528         uffs_DeviceUnLock(obj->dev);
00529         uffs_PutDevice(obj->dev);
00530         obj->dev = NULL;
00531     }
00532 
00533     return U_FAIL;
00534 }
00535 
00536 URET uffs_OpenObject(uffs_Object *obj, const char *fullname, int oflag, int pmode)
00537 {
00538     URET ret = U_FAIL;
00539 
00540     if (_PrepareOpenObj(obj, fullname, oflag, pmode) == U_SUCC)
00541         ret = _OpenObjectUnder(obj);
00542 
00543     if(ret == U_FAIL)
00544         _ReleaseObjectResource(obj);
00545 
00546     return ret;
00547 }
00548 
00549 static void _ReleaseObjectResource(uffs_Object *obj)
00550 {
00551     if (obj) {
00552         if(obj->name) {
00553             uffs_MemFree(obj->dev, obj->name);
00554             obj->name = NULL;
00555         }
00556         if (obj->dev) {
00557             if (HAVE_BADBLOCK(obj->dev)) uffs_RecoverBadBlock(obj->dev);
00558             while (obj->devLockCount > 0) {
00559                 uffs_ObjectDevUnLock(obj);
00560             }
00561             uffs_PutDevice(obj->dev);
00562             obj->dev = NULL;
00563         }
00564     }
00565 }
00566 
00567 URET uffs_CloseObject(uffs_Object *obj)
00568 {
00569     uffs_Device *dev;
00570     uffs_Buf *buf;
00571     uffs_fileInfo fi;
00572 
00573     if(obj == NULL || obj->dev == NULL) return U_FAIL;
00574     if (obj->openSucc != U_TRUE) goto out;
00575 
00576     dev = obj->dev;
00577     uffs_ObjectDevLock(obj);
00578 
00579     if(obj->oflag & (UO_WRONLY|UO_RDWR|UO_APPEND|UO_CREATE|UO_TRUNC)) {
00580 
00581 #ifdef CHANGE_MODIFY_TIME
00582         if (obj->node) {
00583             //need to change the last modify time stamp
00584             if (obj->type == UFFS_TYPE_DIR)
00585                 buf = uffs_BufGetEx(dev, UFFS_TYPE_DIR, obj->node, 0);
00586             else
00587                 buf = uffs_BufGetEx(dev, UFFS_TYPE_FILE, obj->node, 0);
00588 
00589             if(buf == NULL) {
00590                 uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't get file header\n");
00591                 uffs_BufFlush(dev);
00592                 goto out;
00593             }
00594             uffs_BufRead(dev, buf, &fi, 0, sizeof(uffs_fileInfo));
00595             fi.lastModify = uffs_GetCurDateTime();
00596             uffs_BufWrite(dev, buf, &fi, 0, sizeof(uffs_fileInfo));
00597             uffs_BufPut(dev, buf);
00598         }
00599 #endif
00600 
00601         uffs_BufFlush(dev);
00602     }
00603     uffs_ObjectDevUnLock(obj);
00604 
00605 out:
00606     _ReleaseObjectResource(obj);
00607 
00608     return U_SUCC;
00609 }
00610 
00611 static u16 _GetFdnByOfs(uffs_Object *obj, u32 ofs)
00612 {
00613     uffs_Device *dev = obj->dev;
00614     if(ofs < obj->pagesOnHead * dev->com.pgDataSize) {
00615         return 0;
00616     }
00617     else {
00618         ofs -= obj->pagesOnHead * dev->com.pgDataSize;
00619         return (ofs / (dev->com.pgDataSize * dev->attr.pages_per_block)) + 1;
00620     }
00621 }
00622 
00623 static u16 _GetPageIdByOfs(uffs_Object *obj, u32 ofs)
00624 {
00625     uffs_Device *dev = obj->dev;
00626     if(ofs < obj->pagesOnHead * dev->com.pgDataSize) {
00627         return (ofs / dev->com.pgDataSize) + 1; //in file header, pageID start from 1, not 0
00628     }
00629     else {
00630         ofs -= (obj->pagesOnHead * dev->com.pgDataSize);
00631         ofs %= (dev->com.pgDataSize * dev->attr.pages_per_block);
00632         return ofs / dev->com.pgDataSize;
00633     }
00634 }
00635 
00636 static UBOOL _IsAtTheStartOfBlock(uffs_Object *obj, u32 ofs)
00637 {
00638     uffs_Device *dev = obj->dev;
00639     int n;
00640 
00641     if((ofs % dev->com.pgDataSize) != 0) return U_FALSE;
00642     if(ofs < obj->pagesOnHead * dev->com.pgDataSize) {
00643         return U_FALSE;
00644     }
00645     else {
00646         n = ofs - (obj->pagesOnHead * dev->com.pgDataSize);
00647         if(n % (dev->com.pgDataSize * dev->attr.pages_per_block) == 0) return U_TRUE;
00648     }
00649 
00650     return U_FALSE;
00651 }
00652 
00653 static u32 _GetStartOfDataBlock(uffs_Object *obj, u16 fdn)
00654 {
00655     if(fdn == 0) {
00656         return 0;
00657     }
00658     else {
00659         return (obj->pagesOnHead * obj->dev->com.pgDataSize) +
00660             (fdn - 1) * (obj->dev->com.pgDataSize * obj->dev->attr.pages_per_block);
00661     }
00662 }
00663 
00664 
00665 static int _WriteNewBlock(uffs_Object *obj,
00666                           const void *data, u32 len,
00667                           u16 father,
00668                           u16 serial)
00669 {
00670     uffs_Device *dev = obj->dev;
00671     u16 pageID;
00672     int wroteSize = 0;
00673     int size;
00674     uffs_Buf *buf;
00675     URET ret;
00676 
00677     for(pageID = 0; pageID < dev->attr.pages_per_block; pageID++) {
00678         size = (len - wroteSize) > dev->com.pgDataSize ?
00679             dev->com.pgDataSize : len - wroteSize;
00680         if(size <= 0) break;
00681 
00682         buf = uffs_BufNew(dev, UFFS_TYPE_DATA, father, serial, pageID);
00683         if(buf == NULL) {
00684             uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't create a new page ?\n");
00685             break;
00686         }
00687         ret = uffs_BufWrite(dev, buf, (u8 *)data + wroteSize, 0, size);
00688         uffs_BufPut(dev, buf);
00689 
00690         if(ret != U_SUCC) {
00691             uffs_Perror(UFFS_ERR_SERIOUS, PFX"write data fail!\n");
00692             break;
00693         }
00694         wroteSize += size;
00695         obj->node->u.file.len += size;
00696     }
00697     return wroteSize;
00698 }
00699 
00700 static int _WriteInternalBlock(uffs_Object *obj,
00701                                TreeNode *node,
00702                                u16 fdn,
00703                                const void *data,
00704                                u32 len,
00705                                u32 blockOfs)
00706 {
00707     uffs_Device *dev = obj->dev;
00708     u16 maxPageID;
00709     u16 pageID;
00710     u32 size;
00711     u32 pageOfs;
00712     u32 wroteSize = 0;
00713     URET ret;
00714     uffs_Buf *buf;
00715     u32 startOfBlock;
00716     u8 type;
00717     u16 father, serial;
00718 
00719     startOfBlock = _GetStartOfDataBlock(obj, fdn);
00720     if(fdn == 0) {
00721         type = UFFS_TYPE_FILE;
00722         father = node->u.file.father;
00723         serial = node->u.file.serial;
00724     }
00725     else {
00726         type = UFFS_TYPE_DATA;
00727         father = node->u.data.father;
00728         serial = fdn;
00729     }
00730 
00731     if(fdn == 0) maxPageID = obj->pagesOnHead;
00732     else maxPageID = dev->attr.pages_per_block - 1;
00733 
00734 
00735     while(wroteSize < len) {
00736         pageID = blockOfs / dev->com.pgDataSize;
00737         if(fdn == 0) pageID++; //in file header, pageID start from 1, not 0.
00738         if(pageID > maxPageID) break;
00739 
00740         pageOfs = blockOfs % dev->com.pgDataSize;
00741         size = (len - wroteSize + pageOfs) > dev->com.pgDataSize ?
00742             (dev->com.pgDataSize - pageOfs) : (len - wroteSize);
00743 
00744         if((obj->node->u.file.len % dev->com.pgDataSize) == 0 &&
00745             (blockOfs + startOfBlock) == obj->node->u.file.len) {
00746 
00747             buf = uffs_BufNew(dev, type, father, serial, pageID);
00748             if(buf == NULL) {
00749                 uffs_Perror(UFFS_ERR_SERIOUS, PFX"can create a new buf!\n");
00750                 break;
00751             }
00752         }
00753         else {
00754             buf = uffs_BufGetEx(dev, type, node, pageID);
00755             if(buf == NULL) {
00756                 uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't get buffer ?\n");
00757                 break;
00758             }
00759         }
00760 
00761         ret = uffs_BufWrite(dev, buf, (u8 *)data + wroteSize, pageOfs, size);
00762         uffs_BufPut(dev, buf);
00763         if(ret == U_FAIL) {
00764             uffs_Perror(UFFS_ERR_SERIOUS, PFX"write inter data fail!\n");
00765             break;
00766         }
00767 
00768         wroteSize += size;
00769         blockOfs += size;
00770 
00771         if(startOfBlock + blockOfs > obj->node->u.file.len)
00772             obj->node->u.file.len = startOfBlock + blockOfs;
00773 
00774     }
00775 
00776     return wroteSize;
00777 }
00778 
00779 
00780 
00788 int uffs_WriteObject(uffs_Object *obj, const void *data, int len)
00789 {
00790     uffs_Device *dev = obj->dev;
00791     TreeNode *fnode = obj->node;
00792     int remain = len;
00793     u16 fdn;
00794     u32 write_start;
00795     TreeNode *dnode;
00796     u32 size;
00797 
00798     if (obj == NULL) return 0;
00799     if (obj->dev == NULL || obj->openSucc == U_FALSE) return 0;
00800 
00801     if (obj->type == UFFS_TYPE_DIR) {
00802         uffs_Perror(UFFS_ERR_NOISY, PFX"Can't write to an dir object!\n");
00803         return 0;
00804     }
00805 
00806     if(obj->pos > fnode->u.file.len) return 0; //can't write file out of range
00807 
00808     uffs_ObjectDevLock(obj);
00809 
00810     if(obj->oflag == UO_RDONLY) return 0;
00811     if(obj->oflag & UO_APPEND) obj->pos = fnode->u.file.len;
00812 
00813     while(remain > 0) {
00814 
00815         write_start = obj->pos + len - remain;
00816         if(write_start > fnode->u.file.len) {
00817             uffs_Perror(UFFS_ERR_SERIOUS, PFX"write point out of file ?\n");
00818             break;
00819         }
00820 
00821         fdn = _GetFdnByOfs(obj, write_start);
00822 
00823         if(write_start == fnode->u.file.len && fdn > 0 &&
00824             write_start == _GetStartOfDataBlock(obj, fdn)) {
00825             if(dev->tree.erasedCount < MINIMUN_ERASED_BLOCK) {
00826                 uffs_Perror(UFFS_ERR_NOISY, PFX"insufficient block in write obj, new block\n");
00827                 break;
00828             }
00829             size = _WriteNewBlock(obj, (u8 *)data + len - remain, remain, fnode->u.file.serial, fdn);
00830 
00831             //Flush immediately, so that the new data node will be created and put in the tree.
00832             uffs_BufFlush(dev);
00833 
00834             if(size == 0) break;
00835             remain -= size;
00836         }
00837         else {
00838 
00839             if(fdn == 0)
00840                 dnode = obj->node;
00841             else
00842                 dnode = uffs_FindDataNode(dev, fnode->u.file.serial, fdn);
00843 
00844             if(dnode == NULL) {
00845                 uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't find data node in tree ?\n");
00846                 break;
00847             }
00848             size = _WriteInternalBlock(obj, dnode, fdn,
00849                                     (u8 *)data + len - remain, remain,
00850                                     write_start - _GetStartOfDataBlock(obj, fdn));
00851 #ifdef FLUSH_BUF_AFTER_WRITE
00852             uffs_BufFlush(dev);
00853 #endif
00854             if(size == 0) break;
00855             remain -= size;
00856         }
00857     }
00858 
00859     obj->pos += (len - remain);
00860 
00861     if (HAVE_BADBLOCK(dev)) uffs_RecoverBadBlock(dev);
00862 
00863     uffs_ObjectDevUnLock(obj);
00864 
00865     return len - remain;
00866 }
00867 
00875 int uffs_ReadObject(uffs_Object *obj, void *data, int len)
00876 {
00877     uffs_Device *dev = obj->dev;
00878     TreeNode *fnode = obj->node;
00879     u32 remain = len;
00880     u16 fdn;
00881     u32 read_start;
00882     TreeNode *dnode;
00883     u32 size;
00884     uffs_Buf *buf;
00885     u32 blockOfs;
00886     u16 pageID;
00887     u8 type;
00888     u32 pageOfs;
00889 
00890     if (obj == NULL) return 0;
00891     if (obj->dev == NULL || obj->openSucc == U_FALSE) return 0;
00892 
00893 
00894     if (obj->type == UFFS_TYPE_DIR) {
00895         uffs_Perror(UFFS_ERR_NOISY, PFX"Can't read from a dir object!\n");
00896         return 0;
00897     }
00898 
00899     if(obj->pos > fnode->u.file.len) return 0; //can't read file out of range
00900     if(obj->oflag & UO_WRONLY) return 0;
00901 
00902     uffs_ObjectDevLock(obj);
00903 
00904     while(remain > 0) {
00905         read_start = obj->pos + len - remain;
00906         if(read_start >= fnode->u.file.len) {
00907             //uffs_Perror(UFFS_ERR_NOISY, PFX"read point out of file ?\n");
00908             break;
00909         }
00910 
00911         fdn = _GetFdnByOfs(obj, read_start);
00912         if(fdn == 0) {
00913             dnode = obj->node;
00914             type = UFFS_TYPE_FILE;
00915         }
00916         else {
00917             type = UFFS_TYPE_DATA;
00918             dnode = uffs_FindDataNode(dev, fnode->u.file.serial, fdn);
00919             if(dnode == NULL) {
00920                 uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't get data node in entry!\n");
00921                 break;
00922             }
00923         }
00924 
00925         blockOfs = _GetStartOfDataBlock(obj, fdn);
00926         pageID = (read_start - blockOfs) / dev->com.pgDataSize;
00927 
00928         if(fdn == 0) {
00933             pageID++;
00934         }
00935 
00936         buf = uffs_BufGetEx(dev, type, dnode, (u16)pageID);
00937         if(buf == NULL) {
00938             uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't get buffer when read obj.\n");
00939             break;
00940         }
00941 
00942         pageOfs = read_start % dev->com.pgDataSize;
00943         if(pageOfs >= buf->dataLen) {
00944             //uffs_Perror(UFFS_ERR_NOISY, PFX"read data out of page range ?\n");
00945             uffs_BufPut(dev, buf);
00946             break;
00947         }
00948         size = (remain + pageOfs > buf->dataLen ? buf->dataLen - pageOfs: remain);
00949 
00950         uffs_BufRead(dev, buf, (u8 *)data + len - remain, pageOfs, size);
00951         uffs_BufPut(dev, buf);
00952 
00953         remain -= size;
00954     }
00955 
00956     obj->pos += (len - remain);
00957 
00958     if (HAVE_BADBLOCK(dev)) uffs_RecoverBadBlock(dev);
00959 
00960     uffs_ObjectDevUnLock(obj);
00961 
00962     return len - remain;
00963 }
00964 
00972 long uffs_SeekObject(uffs_Object *obj, long offset, int origin)
00973 {
00974     if (obj->type == UFFS_TYPE_DIR) {
00975         uffs_Perror(UFFS_ERR_NOISY, PFX"Can't seek a dir object!\n");
00976         return 0;
00977     }
00978 
00979     uffs_ObjectDevLock(obj);
00980 
00981     switch(origin) {
00982         case USEEK_CUR:
00983             if(obj->pos + offset > obj->node->u.file.len) {
00984                 obj->pos = obj->node->u.file.len;
00985             }
00986             else {
00987                 obj->pos += offset;
00988             }
00989             break;
00990         case USEEK_SET:
00991             if(offset > (long) obj->node->u.file.len) {
00992                 obj->pos = obj->node->u.file.len;
00993             }
00994             else {
00995                 obj->pos = offset;
00996             }
00997             break;
00998         case USEEK_END:
00999             if ( offset>0 ) {
01000                 obj->pos = obj->node->u.file.len;
01001             }
01002             else if((offset >= 0 ? offset : -offset) > (long) obj->node->u.file.len) {
01003                 obj->pos = 0;
01004             }
01005             else {
01006                 obj->pos = obj->node->u.file.len + offset;
01007             }
01008             break;
01009     }
01010 
01011     uffs_ObjectDevUnLock(obj);
01012 
01013     return (long) obj->pos;
01014 }
01015 
01021 int uffs_GetCurOffset(uffs_Object *obj)
01022 {
01023     if (obj) {
01024         if (obj->dev && obj->openSucc == U_TRUE)
01025             return obj->pos;
01026     }
01027     return -1;
01028 }
01029 
01035 int uffs_EndOfFile(uffs_Object *obj)
01036 {
01037     if (obj) {
01038         if (obj->dev && obj->type == UFFS_TYPE_FILE && obj->openSucc == U_TRUE) {
01039             if (obj->pos >= obj->node->u.file.len) {
01040                 return 1;
01041             }
01042             else {
01043                 return 0;
01044             }
01045         }
01046     }
01047 
01048     return -1;
01049 }
01050 
01051 static URET _CoverOnePage(uffs_Device *dev,
01052                           uffs_Tags *old,
01053                           uffs_Tags *newTag,
01054                           u16 newBlock,
01055                           u16 page,
01056                           int newTimeStamp,
01057                           uffs_Buf *buf,
01058                           u32 length)
01059 {
01060     newTag->father = buf->father;
01061     newTag->serial = buf->serial;
01062     newTag->type = buf->type;
01063     newTag->blockTimeStamp = newTimeStamp;
01064     newTag->dataLength = length;
01065     newTag->dataSum = old->dataSum;
01066     newTag->pageID = (u8)(buf->pageID);
01067 
01068 
01069     return uffs_WriteDataToNewPage(dev, newBlock, page, newTag, buf);
01070 }
01071 
01072 static URET _TruncateInternalWithBlockRecover(uffs_Object *obj, u16 fdn, u32 remain)
01073 {
01074     uffs_Device *dev = obj->dev;
01075     TreeNode *fnode = obj->node;
01076     u16 pageID, maxPageID;
01077     TreeNode *node, *newNode;
01078     u16 block, newBlock;
01079     uffs_blockInfo *bc = NULL, *newBc = NULL;
01080     uffs_Buf *buf = NULL;
01081     uffs_Tags *tag, *newTag;
01082     URET ret = U_FAIL;
01083     u8 type;
01084     u32 startOfBlock;
01085     u32 end;
01086     int timeStamp;
01087     u16 page;
01088 
01089     if(fdn == 0) {
01090         node = fnode;
01091         block = node->u.file.block;
01092         type = UFFS_TYPE_FILE;
01093         maxPageID = obj->pagesOnHead;
01094     }
01095     else {
01096         node = uffs_FindDataNode(dev, fnode->u.file.serial, fdn);
01097         if(node == NULL) {
01098             uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't find data node when truncate obj\n");
01099             goto _err;
01100         }
01101         block = node->u.data.block;
01102         type = UFFS_TYPE_DATA;
01103         maxPageID = dev->attr.pages_per_block - 1;
01104     }
01105 
01106 
01107     bc = uffs_GetBlockInfo(dev, block);
01108     if(bc == NULL) {
01109         uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't get block info when truncate obj\n");
01110         goto _err;
01111     }
01112 
01113     newNode = uffs_GetErased(dev);
01114     if(newNode == NULL) {
01115         uffs_Perror(UFFS_ERR_NOISY, PFX"insufficient erased block, can't truncate obj.\n");
01116         goto _err;
01117     }
01118     newBlock = newNode->u.list.block;
01119     newBc = uffs_GetBlockInfo(dev, newBlock);
01120     if(newBc == NULL) {
01121         uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't get block info when truncate obj\n");
01122         goto _err;
01123     }
01124 
01125     startOfBlock = _GetStartOfDataBlock(obj, fdn);
01126     timeStamp = uffs_GetBlockTimeStamp(dev, bc);
01127     timeStamp = uffs_GetNextBlockTimeStamp(timeStamp);
01128 
01129     for(pageID = 0; pageID <= maxPageID; pageID++) {
01130         page = uffs_FindPageInBlockWithPageId(dev, bc, pageID);
01131         if(page == UFFS_INVALID_PAGE) {
01132             uffs_Perror(UFFS_ERR_SERIOUS, PFX"unknown error, truncate\n");
01133             break;
01134         }
01135         page = uffs_FindBestPageInBlock(dev, bc, page);
01136         buf = uffs_BufClone(dev, NULL);
01137         if(buf == NULL) {
01138             uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't clone page buffer\n");
01139             goto _err;
01140         }
01141         tag = &(bc->spares[page].tag);
01142         uffs_LoadPhiDataToBuf(dev, buf, bc->blockNum, page);
01143 
01144         buf->father = tag->father;
01145         buf->serial = tag->serial;
01146         buf->type = tag->type;
01147         buf->pageID = tag->pageID;
01148         buf->dataLen = tag->dataLength;
01149 
01150         newTag = &(newBc->spares[pageID].tag);
01151         if(fdn == 0 && pageID == 0) {
01152             //copy the page file infomation
01153             ret = _CoverOnePage(dev, tag, newTag, newBlock, pageID, timeStamp, buf, buf->dataLen);
01154             if(ret != U_SUCC) break;
01155         }
01156         else {
01157             end = ((fdn == 0) ? (pageID - 1) * dev->com.pgDataSize :
01158                     pageID * dev->com.pgDataSize);
01159             end += tag->dataLength;
01160             end += startOfBlock;
01161 
01162             if(remain > end) {
01163                 if(tag->dataLength != dev->com.pgDataSize) {
01164                     uffs_Perror(UFFS_ERR_NOISY, PFX" ???? unknown error when truncate. \n");
01165                     break;
01166                 }
01167                 ret = _CoverOnePage(dev, tag, newTag, newBlock, pageID, timeStamp, buf, buf->dataLen);
01168                 if(ret != U_SUCC) break;
01169             }
01170             else if(remain == end) {
01171                 ret = _CoverOnePage(dev, tag, newTag, newBlock, pageID, timeStamp, buf, buf->dataLen);
01172                 if(ret != U_SUCC) break;
01173             }
01174             else if(remain < end) {
01175                 buf->dataLen = tag->dataLength - (end - remain);
01176                 if(buf->dataLen == 0) {
01177                     ret = U_SUCC;
01178                     break;
01179                 }
01180                 memset(buf->data + buf->dataLen, 0, dev->com.pgDataSize - buf->dataLen);
01181                 ret = _CoverOnePage(dev, tag, newTag, newBlock, pageID, timeStamp, buf, buf->dataLen);
01182                 break;
01183             }
01184         }
01185         uffs_BufFreeClone(dev, buf);
01186         buf = NULL;
01187     }
01188 
01189 _err:
01190     if(buf != NULL) {
01191         uffs_BufFreeClone(dev, buf);
01192         buf = NULL;
01193     }
01194     if(ret == U_SUCC) {
01195         //ok, modify the tree, and erase old block
01196         uffs_SetTreeNodeBlock(type, node, newNode->u.list.block);
01197         newNode->u.list.block = block;
01198         dev->ops->EraseBlock(dev, newNode->u.list.block);
01199         uffs_InsertToErasedListTail(dev, newNode);
01200     }
01201     else {
01202         //fail to cover block, so erase new block
01203         dev->ops->EraseBlock(dev, newBlock);
01204         uffs_InsertToErasedListTail(dev, newNode);
01205     }
01206 
01207     if(bc) uffs_ExpireBlockInfo(dev, bc, UFFS_ALL_PAGES);
01208     if(bc) uffs_PutBlockInfo(dev, bc);
01209     if(newBc) uffs_ExpireBlockInfo(dev, newBc, UFFS_ALL_PAGES);
01210     if(newBc) uffs_PutBlockInfo(dev, newBc);
01211 
01212     return U_SUCC;
01213 }
01214 
01215 
01216 URET uffs_TruncateObject(uffs_Object *obj, u32 remain)
01217 {
01218     uffs_Device *dev = obj->dev;
01219     TreeNode *fnode = obj->node;
01220     u16 fdn;
01221     u32 flen;
01222     u32 startOfBlock;
01223     TreeNode *node;
01224     uffs_blockInfo *bc;
01225     uffs_Buf *buf;
01226     u16 page;
01227 
01228     if (obj == NULL) return U_FAIL;
01229     if (obj->dev == NULL || obj->openSucc == U_FALSE) return U_FAIL;
01230 
01231     /* do nothing if the obj is a dir */
01232     /* TODO: delete fiiles under dir ? */
01233     if (obj->type == UFFS_TYPE_DIR) {
01234         obj->err = UEEXIST;
01235         return U_FAIL;
01236     }
01237 
01238     if(remain > fnode->u.file.len) return U_FAIL;
01239 
01240     uffs_ObjectDevLock(obj);
01241 
01242     uffs_BufFlush(dev); //flush dirty buffers first
01243 
01244     while(fnode->u.file.len > remain) {
01245         flen = fnode->u.file.len;
01246         fdn = _GetFdnByOfs(obj, flen - 1);
01247 
01248         startOfBlock = _GetStartOfDataBlock(obj, fdn);
01249         if(remain <= startOfBlock && fdn > 0) {
01250             node = uffs_FindDataNode(dev, fnode->u.file.serial, fdn);
01251             if(node == NULL) {
01252                 uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't find data node when trancate obj.\n");
01253                 uffs_ObjectDevUnLock(obj);
01254                 return U_FAIL;
01255             }
01256             bc = uffs_GetBlockInfo(dev, node->u.data.block);
01257             if(bc == NULL) {
01258                 uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't get block info when trancate obj.\n");
01259                 uffs_ObjectDevUnLock(obj);
01260                 return U_FAIL;
01261             }
01262             for(page = 0; page < dev->attr.pages_per_block; page++) {
01263                 buf = uffs_BufFind(dev, fnode->u.file.serial, fdn, page);
01264                 if(buf) uffs_BufSetMark(buf, UFFS_BUF_EMPTY);
01265             }
01266             uffs_ExpireBlockInfo(dev, bc, UFFS_ALL_PAGES);
01267             dev->ops->EraseBlock(dev, node->u.data.block);
01268             uffs_BreakFromEntry(dev, UFFS_TYPE_DATA, node);
01269             node->u.list.block = bc->blockNum;
01270             uffs_PutBlockInfo(dev, bc);
01271             uffs_InsertToErasedListTail(dev, node);
01272             fnode->u.file.len = startOfBlock;
01273         }
01274         else {
01275             if(_TruncateInternalWithBlockRecover(obj, fdn, remain) == U_SUCC) {
01276                 fnode->u.file.len = remain;
01277             }
01278             else {
01279                 uffs_Perror(UFFS_ERR_SERIOUS, PFX"fail to truncate obj\n");
01280                 uffs_ObjectDevUnLock(obj);
01281                 return U_FAIL;
01282             }
01283         }
01284     }
01285 
01286     if (HAVE_BADBLOCK(dev)) uffs_RecoverBadBlock(dev);
01287 
01288     uffs_ObjectDevUnLock(obj);
01289 
01290     return U_SUCC;
01291 
01292 }
01293 
01294 
01298 URET uffs_DeleteObject(const char * name)
01299 {
01300     uffs_Object *obj;
01301     TreeNode *node;
01302     uffs_Device *dev;
01303     u16 block;
01304     uffs_Buf *buf;
01305     URET ret = U_FAIL;
01306 
01307     obj = uffs_GetObject();
01308     if (obj == NULL) goto err1;
01309 
01310     if (uffs_OpenObject(obj, name, UO_RDWR|UO_DIR, US_IREAD|US_IWRITE) == U_FAIL) {
01311         if (uffs_OpenObject(obj, name, UO_RDWR, US_IREAD|US_IWRITE) == U_FAIL)
01312             goto err1;
01313     }
01314 
01315     uffs_TruncateObject(obj, 0);
01316 
01317     uffs_ObjectDevLock(obj);
01318     dev = obj->dev;
01319 
01320     if (obj->type == UFFS_TYPE_DIR) {
01321         // if the dir is not empty, can't delete it.
01322         node = uffs_FindDirNodeFromTreeWithFather(dev, obj->serial);
01323         if (node != NULL) goto err;
01324 
01325         node = uffs_FindFileNodeFromTreeWithFather(dev, obj->serial);
01326         if (node != NULL) goto err;
01327     }
01328 
01329     block = GET_BLOCK_FROM_NODE(obj);
01330     node = obj->node;
01331 
01332     // before erase the block, we need to take care of the buffer ...
01333     uffs_BufFlush(dev);
01334     if (HAVE_BADBLOCK(dev)) uffs_RecoverBadBlock(dev);
01335 
01336     buf = uffs_BufFind(dev, obj->father, obj->serial, 0);
01337     if (buf) {
01338         //need to expire this buffer ...
01339         if (buf->refCount != 0) {
01340             uffs_Perror(UFFS_ERR_NORMAL, PFX"Try to delete object but still have buf referenced.\n");
01341             goto err;
01342         }
01343         buf->mark = UFFS_BUF_EMPTY; 
01344     }
01345     uffs_BreakFromEntry(dev, obj->type, node);
01346     dev->ops->EraseBlock(dev, block); 
01347     node->u.list.block = block;
01348     uffs_InsertToErasedListTail(dev, node);
01349 
01350     ret = U_SUCC;
01351 err:
01352     uffs_ObjectDevUnLock(obj);
01353 err1:
01354     _ReleaseObjectResource(obj);
01355 
01356     return ret;
01357 }
01358 
01359 URET uffs_RenameObject(const char *old_name, const char *new_name)
01360 {
01361     uffs_Object *obj;
01362     uffs_Device *dev;
01363     TreeNode *node;
01364     uffs_Buf *buf;
01365     uffs_fileInfo fi;
01366     char buf_old[MAX_PATH_LENGTH+2]= {0};
01367     char buf_new[MAX_PATH_LENGTH+2]= {0};
01368     int pos, pos1;
01369     u16 father_new;
01370 
01371     URET ret = U_FAIL;
01372 
01373     if(strlen(old_name) >= MAX_PATH_LENGTH ||
01374         strlen(new_name) >= MAX_PATH_LENGTH) return U_FAIL;
01375     pos = find_maxMatchedMountPoint(old_name);
01376     pos1 = find_maxMatchedMountPoint(new_name);
01377     if (pos <= 0 || pos <= 0 || pos != pos1) {
01378         uffs_Perror(UFFS_ERR_NOISY, PFX"Can't rename object with different mount point\n");
01379         return U_FAIL;
01380     }
01381 
01382     _getpath(old_name, buf_old);
01383     _getpath(new_name, buf_new);
01384 
01385     obj = uffs_GetObject();
01386 
01387     if (obj == NULL) {
01388         uffs_Perror(UFFS_ERR_SERIOUS, PFX"Can't get new object.\n");
01389         return U_FAIL;
01390     }
01391 
01392     if (strcmp(buf_new, "/") == 0) {
01393         father_new = ROOT_DIR_ID;
01394     }
01395     else {
01396         pos = strlen(buf_new);
01397         if (buf_new[pos - 1] == '/') buf_new[pos - 1] = '\0'; //take the last '/' off
01398         if (uffs_OpenObject(obj, buf_new, UO_RDONLY|UO_DIR, US_IREAD) == U_SUCC) {
01399             father_new = obj->serial;
01400             uffs_CloseObject(obj);
01401         }
01402         else {
01403             uffs_Perror(UFFS_ERR_NOISY, PFX"Can't open dir %s\n", buf_new);
01404             goto err;
01405         }
01406     }
01407 
01408     if (uffs_OpenObject(obj, new_name, UO_RDONLY, US_IREAD) == U_SUCC) {
01409         //there already has a file with new name exist!
01410         uffs_CloseObject(obj);
01411         return U_FAIL;
01412     }
01413     if (uffs_OpenObject(obj, new_name, UO_RDONLY|UO_DIR, US_IREAD) == U_SUCC) {
01414         //there already has a dir with new name exist!
01415         uffs_CloseObject(obj);
01416         return U_FAIL;
01417     }
01418     _ReleaseObjectResource(obj);
01419     uffs_PutObject(obj);
01420     obj = uffs_GetObject();
01421 
01422     if (uffs_OpenObject(obj, old_name, UO_RDWR, US_IREAD | US_IWRITE) == U_FAIL) {
01423         if (uffs_OpenObject(obj, old_name, UO_RDWR|UO_DIR, US_IREAD | US_IWRITE) == U_FAIL) {
01424             goto err;
01425         }
01426     }
01427 
01428     dev = obj->dev;
01429     node = obj->node;
01430 
01431     uffs_ObjectDevLock(obj);
01432 
01433     uffs_BufFlush(dev);
01434     buf = uffs_BufGetEx(dev, obj->type, node, 0);
01435     if(buf == NULL) {
01436         uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't get buf when rename!\n");
01437         uffs_ObjectDevUnLock(obj);
01438         uffs_CloseObject(obj);
01439         goto err;
01440     }
01441 
01442     memcpy(&fi, buf->data, sizeof(uffs_fileInfo));
01443     strcpy((char *)(fi.name), _getfilename(new_name));
01444     fi.name_len = strlen(fi.name);
01445     fi.lastModify = uffs_GetCurDateTime();
01446 
01447     obj->sum = uffs_MakeSum16(fi.name, fi.name_len);
01448 
01449     //update the check sum of tree node
01450     if (obj->type == UFFS_TYPE_DIR) {
01451         obj->node->u.dir.checkSum = obj->sum;
01452         obj->node->u.dir.father = father_new;
01453     }
01454     else {
01455         obj->node->u.file.checkSum = obj->sum;
01456         obj->node->u.file.father = father_new;
01457     }
01458 
01459     uffs_BufWrite(dev, buf, &fi, 0, sizeof(uffs_fileInfo));
01460     uffs_BufPut(dev, buf);
01461     uffs_BufFlush(dev);
01462 
01463     uffs_ObjectDevUnLock(obj);
01464     uffs_CloseObject(obj);
01465 
01466     ret = U_SUCC;
01467 
01468 err:
01469     _ReleaseObjectResource(obj);
01470     uffs_PutObject(obj);
01471 
01472     return ret;
01473 }
01474 
01475 
01476 static URET _LoadObjectInfo(uffs_Device *dev, TreeNode *node, uffs_ObjectInfo *info, int type)
01477 {
01478     uffs_Buf *buf;
01479 
01480     buf = uffs_BufGetEx(dev, (u8)type, node, 0);
01481 
01482     if(buf == NULL) {
01483         return U_FAIL;
01484     }
01485 
01486     memcpy(&(info->info), buf->data, sizeof(uffs_fileInfo));
01487 
01488     if (type == UFFS_TYPE_DIR) {
01489         info->len = 0;
01490         info->serial = node->u.dir.serial;
01491     }
01492     else {
01493         info->len = node->u.file.len;
01494         info->serial = node->u.file.serial;
01495     }
01496 
01497     uffs_BufPut(dev, buf);
01498 
01499     return U_SUCC;
01500 }
01501 
01502 URET uffs_GetObjectInfo(uffs_Object *obj, uffs_ObjectInfo *info)
01503 {
01504     uffs_Device *dev = obj->dev;
01505     URET ret = U_FAIL;
01506 
01507     uffs_ObjectDevLock(obj);
01508 
01509     if (obj && obj->dev && info)
01510         ret = _LoadObjectInfo(dev, obj->node, info, obj->type);
01511 
01512     uffs_ObjectDevUnLock(obj);
01513 
01514     return ret;
01515 }
01516 
01517 /* find objects */
01518 URET uffs_OpenFindObject(uffs_FindInfo *f, const char * dir)
01519 {
01520     if (f == NULL) return U_FAIL;
01521 
01522     f->obj = uffs_GetObject();
01523     if (f->obj == NULL) {
01524         uffs_Perror(UFFS_ERR_SERIOUS, PFX"Can't get a new object\n");
01525         goto err;
01526     }
01527 
01528     if (_PrepareOpenObj(f->obj, dir, UO_RDONLY|UO_DIR, US_IREAD|US_IWRITE) == U_FAIL) {
01529         uffs_Perror(UFFS_ERR_NOISY, PFX"Can't prepare open dir %s for read.\n", dir);
01530         goto err;
01531     }
01532 
01533     f->dev = f->obj->dev;
01534 
01535     if (f->obj->nameLen == 0) {
01536         //This is the root dir !!!, do not try to open it !
01537         f->father = ROOT_DIR_ID;
01538     }
01539     else {
01540         if (_OpenObjectUnder(f->obj) == U_FAIL) {
01541             uffs_Perror(UFFS_ERR_NOISY, PFX"Can't open dir %s for read, doesn't exist ?\n", dir);
01542             goto err;
01543         }
01544         f->father = f->obj->serial;
01545     }
01546 
01547 
01548     f->hash = 0;
01549     f->work = NULL;
01550     f->step = 0;
01551 
01552     return U_SUCC;
01553 
01554 err:
01555     if (f->obj) {
01556         _ReleaseObjectResource(f->obj);
01557         uffs_PutObject(f->obj);
01558         f->obj = NULL;
01559     }
01560 
01561     return U_FAIL;
01562 }
01563 
01564 URET uffs_FindFirstObject(uffs_ObjectInfo * info, uffs_FindInfo * f)
01565 {
01566     uffs_Device *dev = f->dev;
01567     TreeNode *node;
01568     u16 x;
01569     URET ret = U_SUCC;
01570 
01571     uffs_DeviceLock(dev);
01572     f->step = 0;
01573 
01574     if (f->step == 0) {
01575         for(f->hash = 0;
01576             f->hash < DIR_NODE_ENTRY_LEN;
01577             f->hash++) {
01578 
01579             x = dev->tree.dirEntry[f->hash];
01580 
01581             while(x != EMPTY_NODE) {
01582                 node = FROM_IDX(x, &(dev->tree.dis));
01583                 if(node->u.dir.father == f->father) {
01584                     f->work = node;
01585                     if (info) ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_DIR);
01586                     uffs_DeviceUnLock(dev);
01587                     return ret;
01588                 }
01589                 x = node->hashNext;
01590             }
01591         }
01592 
01593         //no subdirs, then lookup the files
01594         f->step++;
01595     }
01596 
01597     if(f->step == 1) {
01598         for(f->hash = 0;
01599             f->hash < FILE_NODE_ENTRY_LEN;
01600             f->hash++) {
01601 
01602             x = dev->tree.fileEntry[f->hash];
01603 
01604             while(x != EMPTY_NODE) {
01605                 node = FROM_IDX(x, &(dev->tree.dis));
01606                 if(node->u.file.father == f->father) {
01607                     f->work = node;
01608                     if(info) ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_FILE);
01609                     uffs_DeviceUnLock(dev);
01610                     return ret;
01611                 }
01612                 x = node->hashNext;
01613             }
01614         }
01615         f->step++;
01616     }
01617 
01618     uffs_DeviceUnLock(dev);
01619     return U_FAIL;
01620 }
01621 
01622 URET uffs_FindNextObject(uffs_ObjectInfo *info, uffs_FindInfo * f)
01623 {
01624     uffs_Device *dev = f->dev;
01625     TreeNode *node;
01626     u16 x;
01627     URET ret = U_SUCC;
01628 
01629     if(f->dev == NULL ||
01630         f->work == NULL ||
01631         f->step > 1) return U_FAIL;
01632 
01633     uffs_DeviceLock(dev);
01634 
01635     x = f->work->hashNext;
01636 
01637     if (f->step == 0) { 
01638         while(x != EMPTY_NODE) {
01639             node = FROM_IDX(x, &(dev->tree.dis));
01640             if(node->u.dir.father == f->father) {
01641                 f->work = node;
01642                 if(info) ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_DIR);
01643                 uffs_DeviceUnLock(dev);
01644                 return ret;
01645             }
01646             x = node->hashNext;
01647         }
01648 
01649         f->hash++; //come to next hash entry
01650 
01651         for(; f->hash < DIR_NODE_ENTRY_LEN; f->hash++) {
01652             x = dev->tree.dirEntry[f->hash];
01653             while(x != EMPTY_NODE) {
01654                 node = FROM_IDX(x, &(dev->tree.dis));
01655                 if(node->u.dir.father == f->father) {
01656                     f->work = node;
01657                     if(info) ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_DIR);
01658                     uffs_DeviceUnLock(dev);
01659                     return ret;
01660                 }
01661                 x = node->hashNext;
01662             }
01663         }
01664 
01665         //no subdirs, then lookup files ..
01666         f->step++;
01667         f->hash = 0;
01668         x = EMPTY_NODE;
01669     }
01670 
01671     if (f->step == 1) {
01672 
01673         while(x != EMPTY_NODE) {
01674             node = FROM_IDX(x, &(dev->tree.dis));
01675             if(node->u.file.father == f->father) {
01676                 f->work = node;
01677                 if(info) ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_FILE);
01678                 uffs_DeviceUnLock(dev);
01679                 return ret;
01680             }
01681             x = node->hashNext;
01682         }
01683 
01684         f->hash++; //come to next hash entry
01685 
01686         for(; f->hash < FILE_NODE_ENTRY_LEN; f->hash++) {
01687             x = dev->tree.fileEntry[f->hash];
01688             while(x != EMPTY_NODE) {
01689                 node = FROM_IDX(x, &(dev->tree.dis));
01690                 if(node->u.file.father == f->father) {
01691                     f->work = node;
01692                     if(info) ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_FILE);
01693                     uffs_DeviceUnLock(dev);
01694                     return ret;
01695                 }
01696                 x = node->hashNext;
01697             }
01698         }
01699 
01700         //no any files, stoped.
01701         f->step++;
01702     }
01703 
01704     uffs_DeviceUnLock(dev);
01705     return U_FAIL;
01706 }
01707 
01708 URET uffs_CloseFindObject(uffs_FindInfo * f)
01709 {
01710     if (f == NULL) return U_FAIL;
01711 
01712     if (f->obj) {
01713         /* close dir */
01714         _ReleaseObjectResource(f->obj);
01715         uffs_PutObject(f->obj);
01716         f->obj = NULL;
01717     }
01718 
01719     f->dev = NULL;
01720     f->hash = 0;
01721     f->work = NULL;
01722 
01723     return U_SUCC;
01724 }
01725 
01726 

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